线程1

线程1: 
线程和进程类似,但是线程之间能够共享更多的信息。一个进程中的所有线程可以共享进程文件描述符和内存。 
有了多线程控制,我们可以把我们的程序设计成为在一个进程同时做多个任务,每一个线程做一个独立的任务,这种 
方式可以有以下好处: 
1、通过把每一个事件分配给一个线程处理,可以简化异步事件处理的代码。每一个线程可以用同步编程模型,而同步 
编程要比异步编程简单的多。 
2、多个进程需要使用复杂的机制来共享内存和文件描述符。而线程可以自动共享同一内存地址空间和文件描述符。 
3、有一些问题可以划分以便提高这个程序的吞吐量。一个进程如果有多个任务,需要进行隐式的序列化任务,因为 
只有一个线程控制。使用多线程控制,独立的任务可以将每个任务分配一个线程。 
4、交互式的进程可以改善响应时间,通过使用多线程将I/O和程序其他部分分开实现处理。 
多线程不光可以在多核系统中得到并行的优势,而且在单核系统中,也可以提高系统的吞吐量和响应时间,因为当一个线程 
阻塞的时候,另一线程可以占有cpu执行。 
线程有一些描述线程和执行环境的信息来表示它,包括线程ID,寄存器值的集合,栈,调度优先级和策略,信号的掩码,errno 
变量以及线程特有的一些结构。进程中各个线程共享进程的程序执行文本,程序的全局变量、堆内存、栈和文件描述符。 
1、线程标志: 
和进程一样,每一个线程都有一个ID。和进程ID是全系统唯一不同,线程ID是在进程内唯一。进程id用pid_t类型来表示,是一个 
非负的整数。线程ID由pthread_t数据类型代表,和进程一样实现可能为一个结构,所以把pthread_t类型当做一个整数是不具有可 
移植性,所以也没有可移植的打印线程id的方法。这样也需要一个函数来比较两个线程的ID是否相同。 
Cpp代码   收藏代码
  1. #include <pthread.h>  
  2.   
  3. int pthread_equal(pthread_t tid1, pthread_t tid2);  

一个线程可以获得使用pthread_self来获得自己的线程id: 
Cpp代码   收藏代码
  1. #include <pthread.h>  
  2.   
  3. pthread_t pthread_self();  

这个方法 可以和pthread_equal配合使用,来识别被打上线程标记的数据结构。 
2、进程创建: 
通过调用pthread_create可以创建一个线程: 
Cpp代码   收藏代码
  1. #include <pthread.h>  
  2.   
  3. int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *),void *restrict arg);  

创建成功tidp返回线程的id,attr为线程的属性,新创建的进程会运行start_rtn函数,并传入arg作为参数。如果想传入多个参数到start_rtn 
函数中,需要将它们存储在一个结构体中,并把地址传到arg中。失败返回error code,而它们不设定errno。每个线程一个errno只是为了兼容 
以前的函数而被使用的。多线程中,返回error code要比依赖于全局变量的errno清晰一些。 
例子:创建一个线程,并打印进程id、新创建的线程id和主线程id。 
Cpp代码   收藏代码
  1. #include <pthread.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5.   
  6. pthread_t ntid;  
  7.   
  8. void printids(const char *s){  
  9.     pid_t pid;  
  10.     pthread_t tid;  
  11.     pid = getpid();  
  12.     tid = pthread_self();  
  13.     printf("%s pid %u tid (0x%x) \n",s,(unsigned int)pid,(unsigned int)tid);  
  14. }  
  15.   
  16. void * thr_fn(void *arg){  
  17.     printids("new thread: ");  
  18.     return ((void *) 0);  
  19. }  
  20.   
  21. int main(void){  
  22.     int err;  
  23.     err = pthread_create(&ntid, NULL, thr_fn, NULL);  
  24.     if(err != 0){  
  25.         fprintf(stderr,"create pthread failed: %s",strerror(err));  
  26.         exit(1);  
  27.     }  
  28.     printids("main thread: ");  
  29.     sleep(1);  
  30.     exit(0);  
  31. }  

这个例子有两个地方比较古怪,主要是为了处理主线程和新创建线程的竞争:1)主线程休眠,以防止主线程终止,导致真个进程的终止,新建的线程没有机会 
运行,我们后面介绍pthread_join可以避免这个。2)新的线程获得它的线程id是通过调用pthread_self而不是读取一个共享内存的变量或者传递的参数。这是因为 
主线程不能安全的使用ntid,新的线程可能在调用pthread_create返回之前开始运行。 
3、进程终止 
如果进程内的任何一个线程调用exit,_Exit,_exit,整个进程就会终止。类似的如果信号的默认action是终止进程,那么一个发送到线程的信号会终止整个进程。 
只终止一个线程有三种方式: 
1、线程简单的返回。返回值就是退出码。 
2、线程可以被进程中的另一个线程取消。 
3、线程调用pthread_exit。 
Cpp代码   收藏代码
  1. #include <phtread.h>  
  2.   
  3. void pthread_exit(void *rval_ptr);  

rval_ptr是一个无类型的指针,和传递到进程的单个参数类似。这个指针可以被调用pthread_join的其他的线程得到。 
Cpp代码   收藏代码
  1. #include <pthread.h>  
  2.   
  3. int pthread_join(pthread_t thread,void **rval_ptr);  

调用pthread_join的线程会阻塞,直到指定的线程调用了pthread_exit,从start_rtn中返回,或者被取消。 
如果线程简单的返回,那么rval_ptr被设置成start_rtn的返回值,如果线程被取消,rval_ptr被设置成 
PTHREAD_CANCELED。 
通过调用pthread_join,我们自动将线程设置成为detached状态,所以资源会被清除。如果线程已经处于detached状态, 
那么pthread_join就会失败,返回EINVAL. 
如果我们不关心线程的返回值,那么我们可以把rval_ptr设置为NULL。 
Cpp代码   收藏代码
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4. #include <pthread.h>  
  5.   
  6. void * thr_fun1(void *arg){  
  7.     printf("Thread 1 returning...\n");  
  8.     return ((void *)1);  
  9. }  
  10.   
  11. void * thr_fun2(void *arg){  
  12.     printf("Thread 2 exiting...\n");  
  13.     pthread_exit((void *) 2);  
  14. }  
  15.   
  16. int main(void){  
  17.     int err;  
  18.     pthread_t tid1,tid2;  
  19.     void *tret;  
  20.   
  21.     err = pthread_create(&tid1,NULL,thr_fun1,NULL);  
  22.     if(err != 0){  
  23.         fprintf(stderr,"create thread1 failed: %s",strerror(err));  
  24.         exit(1);  
  25.     }  
  26.     err = pthread_create(&tid2,NULL,thr_fun2,NULL);  
  27.     if(err != 0){  
  28.         fprintf(stderr,"create thread2 failed: %s",strerror(err));  
  29.         exit(1);  
  30.     }  
  31.     err = pthread_join(tid1,&tret);  
  32.     if( err != 0 ){  
  33.         fprintf(stderr,"join thread1 failed: %s",strerror(err));  
  34.         exit(1);  
  35.     }  
  36.       
  37.     printf("Thread 1 exit code %d\n",(int)tret);  
  38.   
  39.     err = pthread_join(tid2,&tret);  
  40.     if( err != 0 ){  
  41.         fprintf(stderr,"join thread2 failed: %s",strerror(err));  
  42.         exit(1);  
  43.     }  
  44.     printf("Thread 2 exit code %d\n",(int)tret);  
  45.     exit(0);  
  46. }  

无类型的指针传递给pthread_create和pthread_exit,使用它可以传递多个值,这个指针可以指向包含复杂的结构。但是需要注意这个结构在调用返回时仍然合法。如果 
这个结构是在调用者的栈中,内存的内容在使用的可能时候已经被改变。比如一个线程申请在栈中申请了一个结构,然后将结构的指针传递给pthread_exit,接着这个 
栈在调用thread_join的时候可能已经被销毁。 
例子: 
Cpp代码   收藏代码
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <pthread.h>  
  4. #include <string.h>  
  5.   
  6. struct foo{  
  7.     int a,b,c,d;  
  8. };  
  9.   
  10. void printfoo(const char *s, const struct foo *fp){  
  11.     printf("%s",s);  
  12.     printf(" structure at 0x%x\n",(unsigned) fp);  
  13.     printf(" foo.a = %d\n", fp->a);  
  14.     printf(" foo.b = %d\n", fp->b);  
  15.     printf(" foo.c = %d\n", fp->c);  
  16.     printf(" foo.d = %d\n", fp->d);  
  17. }  
  18.   
  19. void *thr_fn1(void *arg){  
  20.     struct foo foo = {1,2,3,4};  
  21.     printfoo("thread 1:\n",&foo);  
  22.     pthread_exit((void *)&foo);  
  23. }  
  24.   
  25. void *thr_fn2(void *arg){  
  26.     printf("thread 2: ID is %u\n",(unsigned)pthread_self());  
  27.     pthread_exit((void *)0);  
  28. }  
  29.   
  30. int main(void){  
  31.     int err;  
  32.     pthread_t tid1,tid2;  
  33.     struct foo *fp;  
  34.   
  35.     err = pthread_create(&tid1,NULL,thr_fn1,NULL);  
  36.     if(err != 0){  
  37.         fprintf(stderr,"create thread1 failed: %s",strerror(err));  
  38.         exit(1);  
  39.     }  
  40.     err = pthread_join(tid1,(void *)&fp);  
  41.     if(err != 0){  
  42.         fprintf(stderr,"thread_join failed: %s",strerror(err));  
  43.         exit(1);      
  44.     }  
  45.     sleep(1);  
  46.     printf("Parent starting second thread\n");  
  47.   
  48.     err = pthread_create(&tid2,NULL,thr_fn2,NULL);  
  49.     if(err != 0){  
  50.         fprintf(stderr,"create thread2 failed: %s",strerror(err));  
  51.         exit(1);  
  52.     }  
  53.     sleep(1);  
  54.     printfoo("Parent:\n",fp);  
  55.     exit(0);  
  56. }  

一个线程可以可以使用pthread_cancel来取消同一进程中的其他线程。 
Cpp代码   收藏代码
  1. #include <pthread.h>  
  2.   
  3. int pthread_cancel(pthread_t tid);  

在默认的条件下,pthread_cancle将会使由tid指定的线程像调用了pthread_exit(PTHREAD_CANCELED)一样,但是一个线程可以选择忽略和如果控制被取消。pthread_cancel 
并不等待线程的终止,而只是发送一个请求。 
一个线程可以注册函数,当它终止的时候被调用,这个和进程使用atexit注册函数,当进程终止的时候调用类似。这个函数比较出名的就是线程清理函数。一个线程可以 
加入多个线程清理函数,这个清理函数保存在栈中,所以执行的顺序和注册的顺序相反: 
Cpp代码   收藏代码
  1. #include <pthread.h>  
  2.   
  3. void pthread_cleanup_push(void (*rtn)(void *), void arg);  
  4. void pthread_cleanup_pop(int execute);  

pthread_cleanup_push来注册清理函数rtn,这个函数有一个参数arg。但一下三种情形之一发生时,注册的清理函数被执行: 
1)调用pthread_exit 
2)作为对取消线程请求(pthread_cancel)的响应。 
3)以非0参数调用pthread_cleanup_pop。 
如果pthread_cleanup_pop被传递0参数,则清除函数不会被调用,但是仍然会清除处于栈顶的清理函数。 
一个限制是这两个函数可能被实现为一个宏,所以在线程的同一作用域必须以匹配的成对出现。pthread_cleanup_push可能有{,而pthread_cleanup_pop可能有匹配这个 
字符的}字符。 
Cpp代码   收藏代码
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <pthread.h>  
  4. #include <string.h>  
  5.   
  6. void cleanup(void *arg){  
  7.     printf("cleanup: %s\n",(char *)arg);  
  8. }  
  9.   
  10. void *thr_fn1(void *arg){  
  11.     printf("thread 1 start\n");  
  12.     pthread_cleanup_push(cleanup,"thread 1 first handler");  
  13.     pthread_cleanup_push(cleanup,"thread 1 second handler");  
  14.     printf("thread 1 push complete\n");  
  15.     if(arg)  
  16.         return ((void *)1);  
  17.     pthread_cleanup_pop(1);  
  18.     pthread_cleanup_pop(1);  
  19.     return ((void *)1);  
  20. }  
  21.   
  22. void *thr_fn2(void *arg){  
  23.     printf("thread 2 start\n");  
  24.     pthread_cleanup_push(cleanup,"thread 2 first handler");  
  25.     pthread_cleanup_push(cleanup,"thread 2 second handler");  
  26.     printf("thread 2 push complete\n");  
  27.     if(arg){  
  28.         pthread_exit((void *)2);  
  29.     }  
  30.     pthread_cleanup_pop(0);  
  31.     pthread_cleanup_pop(0);  
  32.   
  33.     pthread_exit((void *) 2);  
  34. }  
  35.   
  36. int main(void){  
  37.     int err;  
  38.     pthread_t tid1,tid2;  
  39.     void *tret;  
  40.   
  41.     err = pthread_create(&tid1,NULL,thr_fn1,(void *)1);  
  42.     if( err != 0){  
  43.         fprintf(stderr,"create thread1 failed: %s",strerror(err));  
  44.         exit(1);  
  45.     }  
  46.   
  47.     err = pthread_create(&tid2,NULL,thr_fn2,(void *)2);  
  48.     if(err != 0){  
  49.         fprintf(stderr,"create thread 2 failed: %s",strerror(err));  
  50.         exit(1);  
  51.     }  
  52.   
  53.     err = pthread_join(tid1,&tret);  
  54.     if(err != 0){  
  55.         fprintf(stderr,"thread1 join failed: %s",strerror(err));  
  56.         exit(1);  
  57.     }  
  58.     printf("thread 1 exit code %d\n",(int)tret);  
  59.     err = pthread_join(tid2,&tret);  
  60.     if(err != 0){  
  61.         fprintf(stderr,"thread2 join failed: %s",strerror(err));  
  62.         exit(1);  
  63.     }  
  64.     printf("thread 2 exit code %d\n",(int) tret);  
  65.     exit(0);  
  66.   
  67. }  

如果线程从开始例程(start routine)中返回(by return statement),清理函数不会被调用。 

线程的终止状态,直到pthread_join被调用的时候才能得到。如果一个线程已经被detached,这个线程的空间将会被回收。pthread_join不能等待detached的线程,获得其 
终止状态。pthread_join一个detached线程将会失败,并返回EINVAL,我们可以通过pthread_detach来detach一个线程: 
Cpp代码   收藏代码
  1. #include <pthread.h>  
  2.   
  3. int pthread_detach(pthread_t tid);  

4、线程同步 
当多个线程共享相同的内存时,我们需要保证每一个线程都看到一个一致的数据。如果一个线程的变量别的线程不能够读写,或者变量时只读的,那么不会有不一致的状态。 
然而一个线程可以修改一个变量,而其他的进程同时可以读取或者修改它,我们需要同步线程来保证它们访问变量,使用的是一个合法的值。 
1)互斥量(Mutexes): 
我们可以通过pthread提供的互斥量接口来保护我们的数据,确保每次只有一个线程访问。一个mutex基本上是一个锁,我们在访问共享数据的时候设置(上锁),在访问完成 
后释放(解锁)。当我们解锁的互斥量的时候,当有多余一个的线程被阻塞时,所有阻塞在这个锁的进程都被唤醒,变成可以运行的状态,只有一个线程开始运行并设置锁, 
其他的看到互斥量仍然是被锁定,继续等待。 
互斥量使用pthread_mutex_t数据类型,在我们使用一个互斥量变量时,我们必须先初始化它,可以初始化为PTHREAD_MUTEX_INITIALIZER(静态初始化)或者调用 
pthread_mutext_init,如果我们动态申请了互斥量,我们需要调用pthread_mutext_destory来销毁它: 
Cpp代码   收藏代码
  1. #include <pthread.h>  
  2.   
  3. int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t * restrict attr);  
  4. int pthread_mutex_destory(pthread_mutex_t *mutex);  

如果想使用默认的属性来初始化互斥量,我们把attr设置为NULL。 
例子: 
1)静态初始化 
Cpp代码   收藏代码
  1. pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;  

2)动态初始化: 
Cpp代码   收藏代码
  1. int error;  
  2. pthread_mutex_t mylock;  
  3.   
  4. if (error = pthread_mutex_init(&mylock, NULL))  
  5.    fprintf(stderr, "Failed to initialize mylock:%s\n", strerror(error));  

想给一个互斥量上锁,我们调用pthread_mutex_lock.如果mutex已经上锁,调用的线程将会被阻塞,直至信号量解锁。要解锁一个信号量,我们调用phtread_mutex_unlock 
Cpp代码   收藏代码
  1. int pthread_mutex_lock(pthread_mutex_t *mutex);  
  2. int pthread_mutex_trylock(pthread_mutex_t *mutex);  
  3. int pthread_mutex_unlock(pthread_mutex_t *mutex);  

一个线程如果lock一个已经上锁的互斥量,不想被阻塞,那么可以使用pthread_mutex_trylock,如果调用它的时候没有被上锁,就锁住这个互斥量,如果已经上锁, 
就会失败,并返回EBUSY。 
例子: 
我们使用mutex来保护数据结构:当多个进程需要访问动态申请的结构,我们嵌入了引用计数,来保证知道所有线程都使用完它时,我们才释放它。 
Cpp代码   收藏代码
  1. #include <pthread.h>  
  2. #include <stdlib.h>  
  3.   
  4. struct foo{  
  5.     int f_count;  
  6.     pthread_mutex_t f_lock;  
  7.     /* ...more stuff here... */  
  8. };  
  9.   
  10. struct foo * foo_alloc(void){  
  11.     struct foo *fp;  
  12.     if((fp = malloc(sizeof(struct foo))) != NULL){  
  13.         fp->f_count = 1;  
  14.         if(pthread_mutex_init(&fp->f_lock,NULL) != 0){  
  15.             free(fp);  
  16.             return NULL;  
  17.         }  
  18.     }   
  19.     return fp;  
  20. }  
  21.   
  22. void foo_hold(struct foo *fp){  
  23.     pthread_mutex_lock(&fp->f_lock);  
  24.     fp->f_count++;  
  25.     pthread_mutex_unlock(&fp->f_lock);  
  26. }  
  27.   
  28. void foo_rele(struct foo *fp){  
  29.     pthread_mutex_lock(&fp->f_lock);  
  30.     if(--fp->f_count == 0){  
  31.         pthread_mutex_unlock(&fp->f_lock);  
  32.         pthread_mutex_destroy(&fp->f_lock);  
  33.         free(fp);  
  34.     }else{  
  35.         pthread_mutex_unlock(&fp->f_lock);  
  36.     }  
  37. }  

2)读写锁: 
读写锁也叫共享-排他锁,和互斥量类似,除了它可以提供更高的并行性。使用mutex,它的状态要么处于锁住和未锁状态,只有一个线程可以上锁。而读 
写锁有更多的状态:在读状态锁住,在写状态锁住,未锁住。只有一个线程可以获得写锁,多个线程可以同时获得读锁。当读写锁处于写锁住状态,所有 
试图上锁的进程都被阻塞,当读写锁处于读锁住状态时,所有试图上读状态的锁成功,但是试图获得写状态锁将会被阻塞,直到所有的读进程都释放读状 
态锁,此后来到试图上读锁的线程也被阻塞。 
读写锁适合读比写频繁情形。读写锁和互斥量一样也需要在使用前初始化,在释放他们内存的时候销毁。 
Cpp代码   收藏代码
  1. #include <pthread.h>  
  2.   
  3. int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);  
  4. int pthread_rwlock_destroy(pthread_rwlock_t *restrict rwlock);  

一个读写锁可以调用pthread_rwlock_init来初始化,我们可以传递NULL作为attr的参数,这样会使用读写锁的默认属性。 
我们可以调用pthread_rwlock_destroy来清理,销毁它所占的内存空间。 
上锁: 
Java代码   收藏代码
  1. #include <pthread.h>  
  2.   
  3. int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);  
  4. int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);  
  5. int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);  

实现上可能会对读写锁中读模式的锁锁住次数有一定的限制,所以我们需要检查返回值,以确定是否成功。而其他的两个函数 
会返回错误,但是只要我们的锁设计的恰当,我们可以不必做检查。 
Single UNIX规范另外两个读写锁原语: 
Cpp代码   收藏代码
  1. #include <pthread.h>  
  2.   
  3. int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);  
  4. int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);  

当锁成功获取时,返回0,否则返回EBUSY。这两个函数使用在一个上锁的结构不能够保证产生死锁的时候,它可以避免死锁。 
3)条件变量: 
条件变量时另一中线程同步的机制,允许线程以无竞争的方式等待特定的条件发生。条件变量本身需要互斥量的保护,线程在改变条件前必须首先锁住互斥量, 
且只有在锁住互斥量以后才能计算条件。条件变量使用之前必须首先进行初始化,pthread_cond_t数据类型代表的条件变量可以用两种方式初始化。 
可以把常量PTHREAD_COND_INITIALIZER赋给静态分配的条件变量,但是如果条件变量是动态分配的,可以使用pthread_cond_init函数进行初始化。 
在释放底层的内存空间前,可以使用pthread_mutex_destroy函数对条件变量进行销毁。除非需要创建一个非默认属性的条件变量,否则pthread_cond_init 
函数的attr参数可以设置为NULL。 
Cpp代码   收藏代码
  1. #include <pthread.h>  
  2.   
  3. int pthread_cond_init(pthread_cond_t *restrict cond,  
  4.                       pthread_condattr_t *restrict attr);  
  5. int pthread_cond_destroy(pthread_cond_t *cond);                                           

成功返回0,失败返回错误码。使用pthread_cond_wait等待条件变为真,如果在给定时间内条件不能满足,那么会生成一个代表出错码的返回值。 
调用者需要把锁住的互斥量传给pthread_cond_wait对条件进行保护。函数把调用线程放到等待条件的线程列表上,然后对互斥量解锁,这两个操作 
是原子操作。当pthread_cond_wait返回时,互斥量再次被锁住。 
Cpp代码   收藏代码
  1. #include <pthread.h>   
  2.   
  3. int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);  
  4. int pthread_cond_timewait(pthread_cond_t * restict cond, pthread_mutex_t *restrict mutex,const struct timespec * restrict timeout);  

pthread_cond_timedwait函数的工作方式与pthread_cond_wait函数相似。timeout值指定了等待的时间,它通过timespec结构指定。时间值用秒数或者 
分秒数表示,分秒数的单位是纳秒。时间值是一个绝对数而不是相对数。可以使用gettimeofday获取用timeval结构表示的当前时间,然后把这个时间加 
上要等待的时间转换成timespec结构: 
Cpp代码   收藏代码
  1. void maketimeout(struct timespec *tsp, long minutes){  
  2.     struct timeval now;  
  3.     /* get the current time */  
  4.     gettimeofday(&now);  
  5.     tsp->tv_sec = now.tv_sec;  
  6.     tsp->tv_nsec = now.tv_usec * 10000; /* usec to nsec */  
  7.     tsp->tv_sec += minutes * 60;  
  8. }  

  如果时间值到了但是条件还没有出现,pthread_cond_timedwait将重新获取互斥量,然后返回错误ETIMEDOUT。从pthread_cond_wait或者pthread_cond_timedwait 
调用成功返回时,线程需要重新计算条件,因为其它线程可能已经在运行并改变了条件。pthread_cond_signal函数将唤醒等待该条件的某个线程,而pthread_cond_broadcast 
函数将唤醒等待该条件的所有线程。必须注意一定要在改变条件状态以后再唤醒等待线程 
Cpp代码   收藏代码
  1. #include <pthread.h>  
  2.   
  3. int pthread_cond_signal(pthread_cond_t *cond);  
  4. int pthread_cond_broadcast(pthread_cond_t *cond);     

例子: 
Cpp代码   收藏代码
  1. #include <pthread.h>  
  2.   
  3. struct msg {  
  4.     struct msg *m_next;  
  5.     /* ... more stuff here ... */  
  6. };  
  7.   
  8. struct msg *workq;  
  9. pthread_cond_t qready = PTHREAD_COND_INITIALIZER;   /*初始化条件变量*/  
  10. pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;  /*初始化互斥量*/  
  11.   
  12. void process_msg(void)  
  13. {  
  14.     struct msg *mp;   
  15.   
  16.     for (;;) {  
  17.         pthread_mutex_lock(&qlock);     /*条件本身由互斥量保护*/  
  18.         while (workq == NULL)           /*wait返回后要重新检查条件*/  
  19.             pthread_cond_wait(&qready, &qlock);  /*wait期间释放互斥量,返回时再次锁住*/  
  20.         mp = workq;  
  21.         workq = mp->m_next;  
  22.         pthread_mutex_unlock(&qlock);   /*真正释放互斥量*/  
  23.         /* now process the message mp */  
  24.     }  
  25. }  
  26. void enqueue_msg(struct msg *mp)  
  27. {  
  28.     pthread_mutex_lock(&qlock);       /*修改条件前锁住互斥量*/  
  29.     mp->m_next = workq;  
  30.     workq = mp;  
  31.     pthread_mutex_unlock(&qlock);  
  32.     pthread_cond_signal(&qready);     /*唤醒等待线程时不需要占有互斥量*/  
  33.   
  34.                                      /*如果希望在wait返回时不用再检查条件,就需要在唤醒时占有互斥量*/  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值