390 likes | 505 Views
第十一单元 线程:小心你的邻居. What This Unit is About. This lecture introduces the concepts and more specific calls to handle the real world of POSIX threads programming. In the real world, a programmer needs to worry about protecting data resources from
E N D
第十一单元 线程:小心你的邻居 中山大学-AIX应用程序开发
What This Unit is About • This lecture introduces the concepts and more specific calls to handle • the real world of POSIX threads programming. In the real world, a • programmer needs to worry about protecting data resources from • simultaneous thread updates. A programmer may also be interested in • controlling when a given thread executes and how fast it executes. • What You Should Be Able to Do • After completing this unit, you should be able to: • Protect data resources from multi-thread usage. • Control thread execution. • How You Will Check Your Progress • You can check your progress by completing: • Lab exercise 12 • References: • AIX 5L online documentation
Unit Objectives • Protect data resources from multithread usage. • Control thread execution
Handling Global Data Example (1 of 2) /* global.c */ #include <stdio.h> #include <stdlib.h> #include <pthread.h> int g_count; int g_done; pthread_mutex_t g_count_mutex; void * callFunc(void * notused) { int i; printf("I'm in the child thread now....\n"); for(i=0;i<10;i++) { pthread_mutex_lock(&g_count_mutex); g_count++; pthread_mutex_unlock(&g_count_mutex); printf("Count in CHILD is %d\n", g_count); sleep(1); } g_done = 1; /* Child is done with the mutex */ pthread_exit(NULL); }
Handling Global Data Example (1 of 2) main() { pthread_t callThd; int ret; int i; g_count=0; g_done=0; pthread_mutex_init(&g_count_mutex,NULL); ret=pthread_create(&callThd, NULL, callFunc, NULL); if(ret) { printf("problems on creating thread\n"); exit(EXIT_FAILURE); } for(i=0;i<10;i++) { pthread_mutex_lock(&g_count_mutex); g_count++; pthread_mutex_unlock(&g_count_mutex); printf("Count in PARENT is %d\n", g_count); sleep(1); } while (!g_done) sleep(1); pthread_mutex_destroy(&g_count_mutex); pthread_exit(NULL); }
Thread Specific Data: Example (1 of 2) /* tsd.c */ #include <pthread.h> pthread_key_t count_key; void * thread_starter(void * TID) { int * ptr; int ThreadID; ThreadID=*(int *)TID; ptr=(int *) malloc(sizeof(int)); pthread_setspecific(count_key, ptr); *ptr=0; (*ptr)++; subfunc(); (*ptr)++; printf("Thread %d's count should be 3 now. The pointer says:%d\n",ThreadID, *ptr); *(int *)TID = 0; subfunc(void) int * local_p; local_p=pthread_getspecific(count_key); (*local_p)++; }
Thread Specific Data: Example (2 of 2) void count_key_destructor(void * Data) { free(Data); } main() { pthread_t thd1; pthread_t thd2; int tid1=1, tid2=2; pthread_key_create(&count_key, count_key_destructor); pthread_create(&thd1, NULL, thread_starter, (void *)&tid1); pthread_create(&thd2, NULL, thread_starter, (void *)&tid2); while (tid1 != 0 || tid2 != 0) sleep(1); while(pthread_key_delete(count_key) != 0) sleep(1); pthread_exit(NULL); }
Handling Logic Static Data BEFORE funca() { static int count = 0; count++; printf("count is %d\n", count); } main() { funca(); funca(); } AFTER funca(short funca_count) { printf("count is %d\n", funca_count); } main() { short count = 1; funca(count); count++; funca(count); }
线程安全函数和可重入函数 • 线程安全函数 • 可重入函数
Controlling Execution • Create • Exit • Wait/Interrupt • Cancel • Schedule • Other
Condition Wait Example (1 of 2) /* condwait.c */ #include <signal.h> #include <stdio.h> #include <pthread.h> int Ready=0; pthread_mutex_t m; pthread_cond_t cv; void * slave(void * threadID) { int threadNum = *(int *) threadID; pthread_mutex_lock(&m); while(Ready != 1) pthread_cond_wait(&cv, &m); pthread_mutex_unlock(&m); printf("Thread %d continuing.... \n",threadNum); *(int *)threadID = 0; pthread_exit(NULL); } main() { pthread_t thd1; pthread_t thd2; pthread_t thd3; int j1=1, j2=2, j3=3; pthread_mutex_init(&m,NULL); pthread_cond_init(&cv,NULL); pthread_create(&thd1, NULL, slave, (void * )&j1); pthread_create(&thd2, NULL, slave, (void * )&j2); pthread_create(&thd3, NULL, slave, (void * )&j3);
printf("Main doing work....\n"); sleep(5); /* Simulate work */ pthread_mutex_lock(&m); Ready=1; pthread_cond_broadcast(&cv); pthread_mutex_unlock(&m); printf("Main ready for others and continuing on.... \n"); sleep(5); /* Wait for children to terminate * (using pthread_join with undetached * children would be better) */ while ( j1 != 0 || j2 != 0 || j3 != 0 ) sleep(1); pthread_mutex_destroy(&m); pthread_cond_destroy(&cv); pthread_exit((void *) 0); }
Master/Slave Example (1 of 2) /* master.c */ #include <signal.h> #include <stdio.h> #include <pthread.h> int jobInfo[25]; int jobAvail = 0; int jobPtr=0; /* job data passed to thread */ /* Boolean - # jobs available*/ /* job index for slave thread */ pthread_mutex_t m; pthread_cond_t cv; pthread_key_t key; /* used to protect cv */ /* causes slave to wait for new job */ /* provides TSD data for global jobInfo*/ void * slave(void * threadID) { int threadNum=*(int *) threadID; int * local_job; /* will store jobInfo data */ for(;;) { pthread_mutex_lock(&m); while(jobAvail < 1 && jobPtr < 25) pthread_cond_wait(&cv, &m); if (jobPtr == 25) { pthread_mutex_unlock(&m); /* We're done */ break; } local_job = (int *)malloc(sizeof(int)); /* allocate room for jobInfo*/ pthread_setspecific(key, (void *)local_job); *local_job = jobInfo[jobPtr]; /*global to TSD*/ jobPtr++; /* job handled count goes up */ jobAvail--; /* one less job left */ pthread_mutex_unlock(&m); /* Ready for others to continue*/ printf("Thread %d handling jobthreadNum, *local_job); with local_job info of %d\n", } *(int *)threadID = 0; pthread_exit(NULL); }
Master/Slave Example (2 of 2) main() { pthread_t thd1; pthread_t thd2; pthread_t thd3; int j1=1,j2=2,j3=3; int i; /* thread IDs passed to threads */ /* job index for master thread */ pthread_mutex_init(&m,NULL); pthread_cond_init(&cv,NULL); pthread_create(&thd1, NULL, slave, (void * )&j1); pthread_create(&thd2, NULL, slave, (void * )&j2); pthread_create(&thd3, NULL, slave, (void * )&j3); for(i=0;i< 25;i++) /* create 25 jobs */ { printf("Getting a new job\n"); /*simulates a new job created */ jobInfo[i] = i + 100; /* simulates making data */ pthread_mutex_lock(&m); jobAvail++; pthread_cond_signal(&cv); pthread_mutex_unlock(&m); /* new job available */ } /* Help others finish */ /* (some might be blocked on the pthread_cond_wait call) */ while ( j1 != 0 || j2 != 0 || j3 != 0 ) { pthread_mutex_lock(&m); pthread_cond_signal(&cv); pthread_mutex_unlock(&m); sleep(1); } pthread_mutex_destroy(&m); pthread_cond_destroy(&cv); exit(0); }
Signal Management Example (1 of 2) /* sigmgmt.c */ #include <pthread.h> #include <signal.h> void *threadfunc(void * notused) { struct sigset_t set, oset; sigemptyset(&set); sigaddset(&set, SIGQUIT); sigthreadmask(SIG_BLOCK, &set, NULL); for(;;); /* simulate action */ } void * sigwaiter_thread(void *notused) { int sig; int ret; struct sigset_t set, oset; sigemptyset(&set); sigaddset(&set, SIGQUIT); sigthreadmask(SIG_BLOCK, &set, NULL); for(;;) { sigwait(&set,&sig); printf("sigwait() returned signal = %d\n", sig); } }
Signal Management Example (2 of 2) main() { pthread_t waiterthd, thd; int status; struct sigset_t set, oset; struct sigaction mysig; pthread_attr_t attr; /* Block the signals. */ sigemptyset(&set); sigaddset(&set, SIGQUIT); sigthreadmask(SIG_BLOCK, &set, NULL); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETATCHED); pthread_create(&waiterthd, &attr, sigwaiter_thread, NULL); pthread_create(&thd, &attr, threadfunc, NULL); sleep(2); pthread_join(thd, (void **)&status); printf("Main- check-\n"); }
Cancellation Example (1 of 2) /* pushpop.c */ #include <pthread.h> pthread_mutex_t m; void cleanup_m(void * m) { printf("In cleanup_m handler.\n"); pthread_mutex_unlock((pthread_mutex_t *)m); } void * thread_starter(void * notused) { printf("In thd1.\n"); pthread_mutex_lock(&m); pthread_cleanup_push(cleanup_m, (void *)&m); sleep(1); pthread_testcancel(); /* Cancelation point */ printf("If I reached here, I didn't get canceled.\n"); pthread_mutex_unlock(&m); pthread_cleanup_pop(0); pthread_exit(NULL); }
Cancellation Example (2 of 2) main() { pthread_t thd1; pthread_mutex_init(&m, NULL); pthread_create(&thd1, NULL, thread_starter, NULL); pthread_cancel(thd1); pthread_mutex_destroy(&m); pthread_exit(NULL); }
Scheduling Example (1 of 2) /* thrdsched.c */ #include <pthread.h> void *func1( void *notused) { int priority; struct sched_param sched; pthread_getschedparam(pthread_self(), &priority, &sched); printf("Child thread policy is %d and priority is %d\n", sched.sched_policy, sched.sched_priority); }
Scheduling Example (2 of 2) main() { struct sched_param sched; pthread_attr_t attr; pthread_t thd; printf("Legend:\nPolicy 0 is SCHED_OTHER.\n"); printf("Policy 1 is SCHED_FIFO.\n"); printf("Policy 2 is SCHED_RR.\n\n"); pthread_create( &thd, NULL, func1, NULL); sleep(1); printf("Changing policy of child thread to RR\n"); printf("Changing priority of child thread to 80\n"); pthread_attr_init(&attr); sched.sched_policy = SCHED_RR; sched.sched_priority= 80; pthread_attr_setschedparam(&attr, &sched); pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); pthread_create( &thd, &attr, func1, NULL); pthread_exit(NULL); }
Once Only Initialization • Initialize variable=PTHREAD_ONCE_INIT • Even if many threads call pthread_once(&ariable,routine). • Routine() is called only once. pthread_once(&variable, routine) • is equivalent to: if(variable equals PTHREAD_ONCE_INIT) { routine() change variable }
Once Only Example (1 of 2) /* once.c */ #include <pthread.h> #include <unistd.h> pthread_t thd[2]; static pthread_once_t once = PTHREAD_ONCE_INIT; void init() { pthread_t self; /* Do your initializations here */ /* Check which thread is here */ self = pthread_self(); if(pthread_equal(self,thd[0])) printf("init() - invoked by Thread 1\n"); if(pthread_equal(self,thd[1])) printf("init() - invoked by Thread 2\n"); }
Once Only Example (2 of 2) void * func(void *arg) { pthread_t self; /* init() should be called only once */ (void)pthread_once(&once, init); self = pthread_self(); if(pthread_equal(self,thd[0])) printf("In Thread 1\n"); if(pthread_equal(self,thd[1])) printf("In Thread 2\n"); pthread_exit((void *)1); } main() { pthread_create(&thd[0], NULL, func, 0); pthread_create(&thd[1], NULL, func, 0); pthread_exit( (void **)1); }
Forking Example (1 of 2) /* atfork.c */ #include <pthread.h> #include <sys/types.h> pthread_mutex_t m; void prefork_prepare(void) { printf("prepare\n"); pthread_mutex_lock(&m); } void postfork_parent(void) { printf("parent\n"); pthread_mutex_unlock(&m); } void postfork_child(void) { printf("Child\n"); pthread_mutex_unlock(&m); } void * func(void * arg) { pthread_mutex_lock(&m); sleep(1); printf("In func before unlock\n"); pthread_mutex_unlock(&m); pthread_exit(NULL); }
Forking Example (2 of 2) void * func(void *arg) { pthread_t self; /* init() should be called only once */ (void)pthread_once(&once, init); self = pthread_self(); if(pthread_equal(self,thd[0])) printf("In Thread 1\n"); if(pthread_equal(self,thd[1])) printf("In Thread 2\n"); pthread_exit((void *)1); } main() { pthread_create(&thd[0], NULL, func, 0); pthread_create(&thd[1], NULL, func, 0); pthread_exit( (void **)1); }