160 likes | 379 Views
Нишки в POSIX. гл. ас. Моника Филипова ФМИ, Катедра Изчислителни системи. Съдържание. Основни операции с нишки Създаване на нишка Завършване на нишка Изчакване завършването на нишка Механизъм mutex Създаване на mutex Операции над mutex Механизъм condition Създаване на condition
E N D
Нишки в POSIX гл. ас. Моника ФилиповаФМИ, Катедра Изчислителни системи
Съдържание • Основни операции с нишки • Създаване на нишка • Завършване на нишка • Изчакване завършването на нишка • Механизъм mutex • Създаване на mutex • Операции над mutex • Механизъм condition • Създаване на condition • Операции над condition • Използване на condition
Основни операции с POSIX нишки Създаване на нишка • Първата-главна нишка на процес се създава автоматично. • Друга нишка се създава чрез функцията: #include <pthread.h> int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); thread - идентификатор на създадената нишка attr - атрибути на нишката: • тип на нишката - joinable / detached • дисциплина и параметри при планиране на нишки start_routine -началната функция, която ще се изпълнява в създадената нишката arg- аргумент, предаван на функцията start_routine
Завършване на нишка Нишка завършва когато: • Изпълни return от start_routinе • Извика явно pthread_exit • Друга нишка я прекрати чрез pthread_cancel void pthread_exit(void *retval); retval – "код на завършване" на нишката • Ако нишката е от тип joinable, запомня се кода на завършване retval и нишката минава в състояние зомби. • Ако нишката е от тип detached, изчезва веднага след като изпълни pthread_exit.
Изчакване завършването на нишка int pthread_join(pthread _t thread, void **value_ptr); thread - идентификатор на нишка, чието завършване се чака value_ptr - код на завършване, върнат от нишката thread. • Нишката threadтрябва да е от тип joinable. • Всяка нишка в процес може да се синхронизира със завършването на всяка друга нишка в процеса. • За всяка нишка в процеса може да се изпълни най-много един pthread_join. Връщат 0 при успех, число ≠0 при грешка.
Механизъм mutex • Обект mutex има две състояния • unlocked - свободен и не принадлежи на никоя нишка • locked - заключен и принадлежи на нишката, която го е заключила Създаване на mutex #include <pthread.h> int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *mutexattr); mutex- идентификатор на създадения обект mutexattr- атрибути: тип – fast, recursive, error checking • Обектът е в начално състояние unlocked.
Операции над mutex int pthread_mutex_lock(pthread_mutex_t*mutex); • Ако mutex е свободен, то състоянието му се сменя в заключен от текущата нишка и тя продължава изпълнението. • Ако mutex е заключен от някоя друга нишка, то текущата нишка се блокира, докато се смени състоянието на mutex в unlocked. • Ако mutex е заключен от текущата нишка, то при тип: • fast текущата нишка се блокира • recursive се увеличава брояч и функцията завършва успешно • error checking това се счита за грешка.
Операции над mutex int pthread_mutex_unlock(pthread_mutex_t*mutex); • Ако текущата нишка е настоящия притежател на mutex, то при тип: • fast и error checking се сменя състоянието му в unlocked и ако има нишки, чакащи този mutex, една от тях се събужда. • recursive се намалява брояча и ако стане 0 се освобождава mutex. • Ако mutex е unlocked или е locked, но от друга нишка, то при тип: • error checking и recursive това е грешка • fast не прави проверка. int pthread_mutex_destroy(pthread_mutex_t*mutex); • Унищожава mutex, който трябва да е в състояние отключен. Връщат 0 при успех, число ≠ 0 при грешка.
#include <pthread.h> pthread_mutex_t mut; int sum; main(void) { int ret, cnt1, cnt2; pthread_t th1, th2; void *race_func(); cnt1 = 1; cnt2 = 2; sum = 0; pthread_mutex_init(&mut, NULL); ret = pthread_create(&th1, NULL, race_func, &cnt1); if ( ret != 0) { perror("Error in pthread_create 1"); exit(1); } ret = pthread_create(&th2, NULL, race_func, &cnt2); if ( ret != 0) { perror("Error in pthread_create 2"); exit(1); } pthread_join(th1, NULL); pthread_join(th2, NULL); printf("\nSUM = %d\n", sum); } Пример. Взаимно изключванe
/* Thread function */ void* race_func(void *ptr) { int cnt, i, j; cnt = *(int *)ptr; for (i=1, i <= 100, i++) { pthread_mutex_lock(&mut); sum = sum + cnt; printf("%d\n", sum); pthread_mutex_unlock(&mut); for (j=0;j<400000;j++); /* for some delay */ } pthread_exit((void *)0); }
Механизъм condition • С всеки обект condition е свързано условие, при което нишката може да работи. • Операции над обект condition • wait - нишката се блокира • signal - ако има нишки блокирани по обекта condition, се събужда една, в противен случай нищо не се прави • Използване на обект condition В нишката, която трябва да чака условието за да работи • Проверява условието. • Ако условието не е изпълнено, извиква операцията wait. В нишката, която променя и сигнализира условието • Променя променливите, от които зависи истинноста на условието. • Извиква операцията signal.
Създаване на condition #include <pthread.h> int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *condattr); Операции над condition int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); int pthread_cond_signal(pthread_cond_t *cond); int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_destroy(pthread_cond_t *cond); Връщат 0 при успех, число ≠0 при грешка.
Използване на condition pthread_mutex_t mut; pthread_cond_t cv; • В нишката, която чака условието за да работи pthread_mutex_lock(&mut); while( ! условие_за_да_работи) pthread_cond_wait(&cv, &mut); pthread_mutex_unlock(&mut); • В нишката, която променя и сигнализира условието pthread_mutex_lock(&mut); изменяпроменливите,определящи условието; pthread_cond_signal(&cv); pthread_mutex_unlock(&mut);
#include <pthread.h> #include "ourhdr.h" pthread_mutex_t flag_mut; pthread_cond_t flag_cv; int flag; main(int argc, char *argv[]) { int ret; pthread_t ths, thw; void *th_sign(); void *th_wait(); char *mess1 = "Hello"; char *mess2 = "World"; if ( argc >= 3) { mess1 = argv[1]; mess2 = argv[2]; } ret = pthread_mutex_init(&flag_mut, NULL); pthread_cond_init(&flag_cv, NULL); flag = 0; ret = pthread_create(&thw, NULL, th_wait, mess2); ret = pthread_create(&ths, NULL, th_sign, mess1); pthread_join(thw, NULL); pthread_join(ths, NULL); exit(0); } Пример. Условна синхронизация
/* Signal Thread function */ void *th_sign(void *ptr) { char *msg; msg = (char *)ptr; printf("Signal thread\n"); printf("%s\n", msg); /* Signal the condition: flag is set */ pthread_mutex_lock(&flag_mut); flag = 1; pthread_cond_signal(&flag_cv); pthread_mutex_unlock(&flag_mut); pthread_exit((void *)0); }
/* Wait Thread function */ void *th_wait(void *ptr) { char *msg; msg = (char *)ptr; printf("Wait thread\n"); /* Wait the condition: flag is set */ pthread_mutex_lock(&flag_mut); while( ! flag ) pthread_cond_wait(&flag_cv, &flag_mut); pthread_mutex_unlock(&flag_mut); /* Do the work */ printf("%s\n", msg); pthread_exit((void *)0); }