Sukurti giją galime parašius šį kodą:
int pthread_create(pthread_t *, const pthread_attr_t *, void * (*)(void *), void *);
int
- skaičius, kurį gražina funkcija atitinkamai ar gija buvo sukurta, ar ne.pthread_t *
(unsigned int *
) - rodyklė į vietą, kur funkcija išsaugos gijos identifikatorių.pthread_attr_t *
- rodyklė į tą vietą, kur saugomi gijai būdingi atributai (gali būtiNULL
, tada bus naudojami numatyti atributai.)void * (*)(void *)
- rodyklė į tą vietą, kur yra saugomas funkcijos kodas.void *
- rodyklė į tą vietą, kur saugomas į funkciją paduodamas vienas parametras (gali būti bet kokia reikšmė) Sujungti gijas į vieną pagrindinę galima parašius kodą (C programavimo kalba)
int pthread_join(pthread_t thread, void **retval);
int
- skaičius, kurį gražina funkcija atitinkamai ar gijos buvo sėkmingai sujungtos, ar ne.pthread_t
(unsigned int
) - skaičius reprezentuojantis gijos identifikatorių.void **retval
- rodyklė į rodyklę, kuri nurodo vietą į kurią bus saugoma reikšmė, kuri buvo grąžinama sujungiant giją su esama (įrašiusNULL
, reikšmė ignoruojama)
class thread_data {
public:
int x;
};
void * PrintHello(void * passedData) {
thread_data * myData = reinterpret_cast < thread_data * > (passedData);
cout << "Hello World! From thread " << myData -> x << endl;
delete myData; // free the memory
return NULL;
}
int main(int argc, char * argv[]) {
const int NUM_THREADS = 4;
pthread_t threads[NUM_THREADS];
for (int t = 0; t < NUM_THREADS; t++) {
cout << "In main: creating thread " << t << endl;
thread_data * data = new thread_data();
data -> x = t;
pthread_create( & threads[t], NULL, PrintHello, data);
}
for (int t = 0; t < NUM_THREADS; t++)
pthread_join(threads[t], NULL);
return 0;
}
Barjerai tai yra tam tikri objektai, neleidžiantys procesoriui išdėstyti tam tikras skaitymo, rašymo, skaičiavimo funkcijas, instrukcijų konvejeryje. Tai reikalinga norint dalinai užtikrinti kad nebūtų duomenų lenktynių (angl. data race), paleidžiant keletą gijų vienu metu.
Sukurti barjerą galime parašius šį kodą (C programavimo kalba):
int pthread_barrier_init(pthread_barrier_t *restrict barrier, const pthread_barrierattr_t *restrict attr, unsigned count);
restrict
- raktažodis C programavimo kalboje, kuris skirtas kompiliatoriui optimizuoti rodyklinius parametrus, jeigu rodyklės nesaugo adresų į vienas kitą.pthread_barrier_t *restrict
- rodyklė į vietą, kur funkcija išsaugos barjero identifikatorių.pthread_barrierattr_t *restrict attr
- rodyklė į tą vietą kurioje saugomi atitinkami barjero atributai. (gali būtiNULL
, tada bus naudojami numatyti atributai.)unsigned count
- skaičius, kuris parodo kiek gijų barjeras turi palaikyti, norint užtikrinti jo veikimą.
Pristabdyti giją iki tol kos bus atlikti gijos instrukcijų konvejerio operacijos galime parašius šį kodą (C programavimo kalba):
int pthread_barrier_wait(pthread_barrier_t *barrier);
pthread_barrier_t *
- rodyklė į vietą, kur yra išsaugotas barjero identifikatorius.
Panaikinti barjerą iš heap atminties galima panaudojus ši kodą (C programavimo kalba):
int pthread_barrier_destroy(pthread_barrier_t *barrier);
pthread_barrier_t *
- rodyklė į vietą, kur yra išsaugotas barjero identifikatorius.
Muteksai tai yra tam tikri objektai kuriuos panaudojus, gijos negali paleisti tam tikro kodo fragmento lygiagrečiai. Tai reikalinga norint dalinai užtikrinti kad nebūtų duomenų lenktynių (angl. data race), paleidžiant keletą gijų vienu metu.
Norint sukurti muteksą galima panaudoti šį kodą (C programavimo kalba):
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr)
restrict
- raktažodis C programavimo kalboje, kuris skirtas kompiliatoriui optimizuoti rodyklinius parametrus, jeigu rodyklės nesaugo adresų į vienas kitą.pthread_mutex_t *restrict mutex
- rodyklė į vietą, kur funkcija išsaugos mutekso identifikatorių.
Warning
Mutekso adreso vietą reikia inicializuoti su tam tikra PTHREAD_MUTEX_INITIALIZER
, norint užtikrinti sklandų mutekso sukūrimą. Ta galima padaryti panaudojus šį kodą (C programavimo kalba):
pthread_mutex_t amutex = PTHREAD_MUTEX_INITIALIZER;
Siekiant blokuoti kitas gijas, gijos veikimo metu, mes galime užrakinti muteksą panaudojant šį kodą (C programavimo kalba):
int pthread_mutex_lock(pthread_mutex_t *mutex);
pthread_mutex_t *mutex
- rodyklė į vietą, kur yra išsaugotas mutekso identifikatorius.
Siekiant pasibaigus tam tikram darbui nebeblokuoti kitų gijų, gijos veikimo metu, mes galime atrakinti muteksą panaudojant šį kodą (C programavimo kalba):
int pthread_mutex_unlock(pthread_mutex_t *mutex);
pthread_mutex_t *mutex
- rodyklė į vietą, kur yra išsaugotas mutekso identifikatorius.
Warning
Muteksą užrakinti ir atrakinti reikėtų atsargiai, kadangi neteisingai panaudojus muteksą, gali iškilti vienos kitos gijų užsiblokavimo rizika.
Panaikinti muteksą iš heap atminties galima panaudojant šį kodą (C programavimo kalba):
int pthread_mutex_destroy(pthread_mutex_t *mutex);
pthread_mutex_t *mutex
- rodyklė į vietą, kur yra išsaugotas mutekso identifikatorius.
OpenMP yra taikomųjų programų programavimo sąsaja (API), kuri palaiko kelių platformų bendros atminties kelių procesų programavimą lengvu bei intuityviu būdų, nekeičiant esminio nuoseklaus kodo.
Kad atlikti tam tikrą kodo fragmentą lygiagrečiai, naudojant OpenMP užtenka parašyti tik vieną kodo eilutę prie esamo nuoseklaus kodo (C programavimo kalba):
#pragma omp parallel
std::cout << "Hello, World!\n";
Viršuje esantis kodas padaro tik vieną kodo eilutę veikiančią lygiagrečiai, tačiau jeigu norime paleisti tam tikrą kodo fragmentą didesnį nei vieną eilutę, mes norimą kodą galima apskliausti (C programavimo kalba):
#pragma omp parallel {
int id = omp_get_thread_num();
cout << "Hello, world, from thread - " << id << endl;
if (id == 0) {
int nthreads = omp_get_num_threads();
cout << "Number of threads = " << nthreads << endl;
}
}
Rašyti kodą kuris tik veikia lygiagrečiai bet atlieką tapatį darbą gali atrodyti nepraktiška, todėl OpenMP suteikia galimybę identifikuoti giją, siekiant apskaičiuoti skirtingus duomenis lygiagrečiu būdu. Identifikuoti giją galima panaudojant šį kodą (C programavimo kalba):
int omp_get_thread_num();
int
skaičius, kuris parodo koks gijos numeris šiuo metu atlieka lygiagrečius skaičiavimus.
Siekiant sužinoti kiek iš viso gijų atlieka lygiagrečius skaičiavimus tam tikram kodo fragmentui galima panaudojant šį kodą (C programavimo kalba):
int omp_get_num_threads();
int
skaičius, kuris parodo kiek tam tikras lygiagrečiai veikiantis kodo fragmentas turi gijų.
#pragma omp parallel {
int id = omp_get_thread_num();
std::cout << "Hello, world, from thread - " << id << std::endl;
if (id == 0) {
int nthreads = omp_get_num_threads();
std::cout << "Number of threads = " << nthreads << std::endl;
}
}