博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux 多线程编程
阅读量:6846 次
发布时间:2019-06-26

本文共 18169 字,大约阅读时间需要 60 分钟。

  hot3.png

一、什么是线程?

        线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

二、什么时候使用多线程?    

        当多个任务可以并行执行时,可以为每个任务启动一个线程。

三、线程的基本函数

        大多数pthread_XXX系列的函数在失败时,并未遵循UNIX函数的惯例返回-1,而是返回错误代码;如果调用成功,则返回0。

1)线程创建

#include
int pthread_create (pthread_t *__restrict __newthread,//指向pthread_create的指针, 用于引用新创建的线程 __const pthread_attr_t *__restrict __attr,//用于设置线程的属性,可以简单地设置为NULL void *(*__start_routine) (void *),//新创建的线程执行的函数 void *__restrict __arg)//执行函数的参数

2)线程终止

#include 
void pthread_exit(void *retval);//返回指针,指向线程要返回的某个对象

        线程通过调用pthread_exit函数终止执行,并返回一个指向某对象的指针。注意:绝不能用它返回一个指向局部变量的指针,因为线程调用该函数后,这个局部变量就不存在了,这将引起严重的程序漏洞。

        用pthread_exit只会使主线程自身退出,产生的子线程继续执行;用return则所有线程退出。 

        综合以上要想让子线程总能完整执行(不会中途退出),方法如下:

        (1) 在主线程中调用pthread_join对其等待,即pthread_create / pthread_join / pthread_exit或return

        (2) 一种方法是在主线程退出时使用pthread_exit,这样子线程能继续执行,即pthread_create / pthread_detach / pthread_exit

        (3) 还有一种是pthread_create / pthread_detach / return,这时就要保证主线程不能退出,至少是子线程完成前不能退出。

3)线程同步

#include 
int pthread_join(pthread_t th, void **thread_return);

参数说明:

th:线程ID,标识唯一线程。

thread_return:用户定义的指针,用来存储被等待线程的返回值。

4)线程分离

#include 
int pthread_detach(pthread_t tid);

        linux线程执行和windows不同,pthread有两种状态joinable状态和unjoinable状态。

        如果线程是joinable状态,当线程函数自己返回退出时或pthread_exit时都不会释放线程所占用堆栈和线程描述符。只有当你调用了pthread_join之后这些资源才会被释放。

        若线程是unjoinable状态,这些资源在线程函数退出时或pthread_exit时自动会被释放。unjoinable属性可以在pthread_create时指定,或在线程创建后在线程中pthread_detach自己, 如:

pthread_detach(pthread_self());

将状态改为unjoinable状态,确保资源的释放。或者将线程置为 joinable,然后适时调用pthread_join。

其实简单的说就是在线程函数头加上 pthread_detach(pthread_self())的话,线程状态改变,在函数尾部直接 pthread_exit线程就会自动退出。

5)线程取消

1、 线程取消的函数

#include 
int pthread_cancel(pthread_t thread);

2、设置线程的取消状态

#include 
int pthread_setcancelstate(int state, int *oldstate);

参数说明:

state:可以是PTHREAD_CANCEL_ENABLE允许线程接收取消请求,也可以是PTHREAD_CANCEL_DISABLE忽略取消请求。
oldstate:获取先前的取消状态。如果对它没兴趣,可以简单地设置为NULL。如果取消请求被接受了,线程可以进入第二个控制层次,用pthread_setcanceltype设置取消类型。

3、设置线程的取消类型

#include 
int pthread_setcanceltype(int type, int *oldtype);

参数说明:

type:可以取PTHREAD_CANCEL_ASYNCHRONOUS,它将使得在接收到取消请求后立即采取行动;另一个是PTHREAD_CANCEL_DEFERRED,它将使得在接收到取消请求后,一直等待直到线程执行了下述函数之一后才采取行动:pthread_join、pthread_cond_wait、pthread_cond_timedwait、pthread_testcancel、sem_wait或sigwait。
oldtype:允许保存先前的状态,如果不想知道先前的状态,可以传递NULL。
默认情况下,线程在启动时的取消状态为PTHREAD_CANCEL_ENABLE,取消类型是PTHREAD_CANCEL_DEFERRED。

下面代码是主线程向它创建的线程发送一个取消请求。

#include 
#include
#include
void *thread_function(void *arg); int main() { int res; pthread_t a_thread; void *thread_result; res = pthread_create(&a_thread, NULL, thread_function, NULL); if (res != 0) { perror("Thread create failed!"); exit(EXIT_FAILURE); } sleep(4); printf("Canceling thread.../n"); res = pthread_cancel(a_thread); if (res != 0) { perror("Thread cancel failed!"); exit(EXIT_FAILURE); } printf ("Waiting for thread to finished.../n"); res = pthread_join(a_thread, &thread_result); if (res != 0) { perror ("Thread join failed!"); exit(EXIT_FAILURE); } printf("Thread canceled!"); exit(EXIT_FAILURE); } void *thread_function(void *arg) { int i; int res; res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); if (res != 0) { perror("Thread setcancelstate failed!"); exit(EXIT_FAILURE); } res = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); if (res != 0) { perror("Thread setcanceltype failed!"); exit(EXIT_FAILURE); } printf("thread_function is running.../n"); for (i = 0; i < 10; i++) { printf("Thread is still running (%d).../n", i); sleep(1); } pthread_exit(0); }

运行结果:

thread_function is running...Thread is still running (0)...Thread is still running (1)...Thread is still running (2)...Thread is still running (3)...Canceling thread...Waiting for thread to finished...

5)线程的属性

下面介绍几个常用的函数:

1、初始化线程属性

int pthread_attr_init(pthread_attr_t *attr);/*    返回值:若是成功返回0,否则返回错误的编号    形  参:            attr       指向一个线程属性的指针    说  明:Posix线程中的线程属性主要包括scope属性、detach属性、堆栈地址、堆栈大小、优先级。            pthread_attr_init实现时为属性对象分配了动态内存空间。    头文件:#include 
*/

2、销毁一个线程属性对象

int pthread_attr_destroy(pthread_attr_t *attr);/*    返回值:若是成功返回0,否则返回错误的编号    形  参:            attr       指向一个线程属性的指针    说  明:经pthread_attr_destroy后的属性,再被pthread_create函数调用,将会返回错误。    头文件:#include 
*/

3、获取线程分离状态属性

int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);/*    返回值:若是成功返回0,否则返回错误的编号    形  参:            attr          指向一个线程属性的指针            detachstate   保存返回的分离状态属性    说  明:获取线程分离状态属性    头文件:#include 
*/

4、修改线程分离状态属性

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);/*    返回值:若是成功返回0,否则返回错误的编号    形  参:            attr        指向一个线程属性的指针            detachstat  有两个取值                        PTHREAD_CREATE_DETACHED(分离)                        PTHREAD_CREATE_JOINABLE(非分离)    说  明:修改线程分离状态属性    头文件:#include 
*/

5、获取线程的作用域

int pthread_attr_getscope(pthread_attr_t *attr, int *scope);/*    返回值:若是成功返回0,否则返回错误的编号    形  参:            attr       指向一个线程属性的指针            scope      返回线程的作用域    说  明:指定了作用域也就指定了线程与谁竞争资源    头文件:#include 
*/

6、设置线程的作用域

int pthread_attr_setscope(pthread_attr_t *attr, int scope);/*    返回值:若是成功返回0,否则返回错误的编号    形  参:            attr       指向一个线程属性的指针            guardsize  线程的作用域,可以取如下值                       PTHREAD_SCOPE_SYSTEM    与系统中所有进程中线程竞争                       PTHREAD_SCOPE_PROCESS   与当前进程中的其他线程竞争    说  明:指定了作用域也就指定了线程与谁竞争资源    头文件:#include 
*/

7、获取线程的堆栈信息(栈地址和栈大小)

int pthread_attr_getstack(pthread_attr_t *attr, void **stackaddr, size_t *stacksize);/*    返回值:若是成功返回0,否则返回错误的编号    形  参:            attr       指向一个线程属性的指针            stackaddr  返回获取的栈地址            stacksize  返回获取的栈大小    说  明:获取线程的堆栈地址和大小    头文件:#include 
*/

8、设置线程堆栈区

int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);/*    返回值:若是成功返回0,否则返回错误的编号    形  参:            attr       指向一个线程属性的指针            stackaddr  线程的堆栈地址:应该是可移植的,对齐页边距的                       可以用posix_memalign来进行获取            stacksize  线程的堆栈大小:应该是页大小的整数倍    说  明:设置堆栈区,将导致pthread_attr_setguardsize失效。    头文件:#include 
*/

9、获取线程堆栈地址

int pthread_attr_getstackaddr(pthread_attr_t *attr, void **stackaddr);/*    返回值:若是成功返回0,否则返回错误的编号    形  参:            attr       指向一个线程属性的指针            stackaddr  返回获取的栈地址    说  明:函数已过时,一般用pthread_attr_getstack来代替    头文件:#include 
*/

10、设置线程堆栈地址

int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr);/*    返回值:若是成功返回0,否则返回错误的编号    形  参:            attr       指向一个线程属性的指针            stackaddr  设置线程堆栈地址    说  明:函数已过时,一般用pthread_attr_setstack来代替    头文件:#include 
*/

11、获取线程堆栈大小

int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);/*    返回值:若是成功返回0,否则返回错误的编号    形  参:            attr       指向一个线程属性的指针            stacksize  返回线程的堆栈大小    说  明:获取线程堆栈大小    头文件:#include 
*/

12、设置线程堆栈大小

int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);/*    返回值:若是成功返回0,否则返回错误的编号    形  参:            attr       指向一个线程属性的指针            guardsize  线程的栈保护区大小:应该是页大小的整数倍    说  明:设置线程堆栈大小:    头文件:#include 
*/

13、获取线程的调度策略

int pthread_attr_getschedpolicy(pthread_attr_t *attr, int *policy);/*    返回值:若是成功返回0,否则返回错误的编号    形  参:            attr       指向一个线程属性的指针            policy     返回线程的调度策略    说  明:获取线程的调度策略    头文件:#include 
*/

14、设置线程的调度策略

int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);/*    返回值:若是成功返回0,否则返回错误的编号    形  参:            attr       指向一个线程属性的指针            policy     线程的调度策略,有如下三种:                        SCHED_FIFO    先入先出策略                        SCHED_RR      轮转调度,类似于 FIFO,但加上了时间轮片算法                        SCHED_OTHER      系统默认策略    说  明:设置线程的调度策略    头文件:#include 
*/

15、获取线程的调度参数

int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);/*    返回值:若是成功返回0,否则返回错误的编号    形  参:            attr       指向一个线程属性的指针            param      返回获取的调度参数,该结构仅有一个从参数,如下                        struct sched_param                         {                            int sched_priority; /* Scheduling priority */                        };    说  明:获取线程的调度参数    头文件:#include 
*/

16、设置线程的调度参数

int pthread_attr_getschedparam(pthread_attr_t *attr, struct sched_param *param);/*    返回值:若是成功返回0,否则返回错误的编号    形  参:            attr       指向一个线程属性的指针            param      要设置的调度参数    说  明:设置线程的调度参数    头文件:#include 
*/

6)线程的同步

1、用信号量进行同步

(1) 信号量创建

#include 
int sem_init(sem_t *sem, int pshared, unsigned int value);

参数说明:

sem:信号量对象。
pshared:控制信号量的类型,0表示这个信号量是当前进程的局部信号量,否则,这个信号量就可以在多个进程之间共享。
value:信号量的初始值。

(2) 信号量控制

#include 
int sem_wait(sem_t *sem);int sem_post(sem_t *sem);

sem_post的作用是以原子操作的方式给信号量的值加1。

sem_wait的作用是以原子操作的方式给信号量的值减1,但它会等到信号量非0时才会开始减法操作。如果对值为0的信号量调用sem_wait,这个函数就会等待,直到有线程增加了该信号量的值使其不再为0。

(3) 信号量销毁

#include 
int sem_destory(sem_t *sem);

这个函数的作用是,用完信号量后对它进行清理,清理该信号量所拥有的资源。如果你试图清理的信号量正被一些线程等待,就会收到一个错误。

与大多数Linux函数一样,这些函数在成功时都返回0。

下面编码实现输入字符串,统计每行的字符个数,以“end”结束输入:

#include 
#include
#include
#include
#include
#define SIZE 1024 void *thread_function(void *arg); char buffer[SIZE]; sem_t sem; int main() { int res; pthread_t a_thread; void *thread_result; res = sem_init(&sem, 0, 0); if (res != 0) { perror("Sem init failed"); exit(EXIT_FAILURE); } res = pthread_create(&a_thread, NULL, thread_function, NULL); if (res != 0) { perror("Thread create failed"); exit(EXIT_FAILURE); } printf("Input some text. Enter 'end' to finish/n"); while (scanf("%s", buffer)) { sem_post(&sem); if (strncmp("end", buffer, 3) == 0) break; } printf ("/nWaiting for thread to finish.../n"); res = pthread_join(a_thread, &thread_result); if (res != 0) { perror("Thread join failed"); exit(EXIT_FAILURE); } printf ("Thread join/n"); sem_destroy(&sem); exit(EXIT_SUCCESS); } void *thread_function(void *arg) { sem_wait(&sem); while (strncmp("end", buffer, 3) != 0) { printf("You input %d characters/n", strlen(buffer)); sem_wait(&sem); } pthread_exit(NULL); }

运行结果:

Input some text. Enter 'end' to finish123You input 3 characters1234You input 4 characters12345You input 5 charactersend Waiting for thread to finish…Thread join

2、用互斥量进行线程同步

它允许程序员锁住某个对象,使得每次只能有一个线程访问它。为了控制对关键代码的访问,必须在进入这段代码之前锁住一个互斥量,然后在完成操作之后解锁它。

#include 
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t, *mutexattr);int pthread_mutex_lock(pthread_mutex_t *mutex);//pthread_mutex_trylock()与pthread_mutex_lock()类似,不同的是在锁已经被占据时返回EBUSY而不是挂起等待int pthread_mutex_trylock(pthread_mutex_t *mutex);int pthread_mutex_unlock(pthread_mutex_t *mutex);int pthread_mutex_destory(pthread_mutex_t *mutex);

与其他函数一样,成功时返回0,失败时将返回错误代码,但这些函数并不设置errno,所以必须对函数的返回代码进行检查。互斥量的属性设置这里不讨论,因此设置成NULL。

互斥锁的属性在创建锁的时候指定,在Linux Threads实现中仅有一个锁类型属性,不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。当前有四个值可供选择:

* PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。

* PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。

* PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。

* PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。

我们用互斥量来重写刚才的代码如下:

#include 
#include
#include
#include
#include
#define SIZE 1024 char buffer[SIZE]; void *thread_function(void *arg); pthread_mutex_t mutex; int main() { int res; pthread_t a_thread; void *thread_result; res = pthread_mutex_init(&mutex, NULL); if (res != 0) { perror("Mutex init failed!"); exit(EXIT_FAILURE); } res = pthread_create(&a_thread, NULL, thread_function, NULL); if (res != 0) { perror("Thread create failed!"); exit(EXIT_FAILURE); } printf("Input some text. Enter 'end' to finish/n"); while (1) { pthread_mutex_lock(&mutex); scanf("%s", buffer); pthread_mutex_unlock(&mutex); if (strncmp("end", buffer, 3) == 0) break; sleep(1); } res = pthread_join(a_thread, &thread_result); if (res != 0) { perror("Thread join failed!"); exit(EXIT_FAILURE); } printf("Thread joined/n"); pthread_mutex_destroy(&mutex); exit(EXIT_SUCCESS); } void *thread_function(void *arg) { sleep(1); while (1) { pthread_mutex_lock(&mutex); printf("You input %d characters/n", strlen(buffer)); pthread_mutex_unlock(&mutex); if (strncmp("end", buffer, 3) == 0) break; sleep(1); } }

运行结果:

Input some text. Enter 'end' to finish123You input 3 characters1234You input 4 characters12345You input 5 charactersendYou input 3 charactersThread joined

3、用条件变量进行同步

条件变量条件变量用pthread_cond_t数据类型表示。条件变量本身由互斥量保护,所以在改变条件状态前必须锁住互斥量。

(1) 条件变量初始化:

第一种,赋值常量PTHREAD_COND_INITIALIZER;

第二种,使用pthread_cond_init函数:

int pthread_cond_init (pthread_cond_t *__restrict __cond,   __const pthread_condattr_t *__restrict   __cond_attr);int pthread_cond_destroy (pthread_cond_t *__cond);

(2) 条件等待:

使用pthread_cond_wait等待条件为真。

pthread_cond_wait (pthread_cond_t *__restrict __cond, pthread_mutex_t *__restrict __mutex)

这里需要注意的是,调用pthread_cond_wait传递的互斥量已锁定,pthread_cond_wait将调用线程放入等待条件的线程列表,然后释放互斥量,在pthread_cond_wait返回时,再次锁定互斥量。

(3) 唤醒线程

pthread_cond_signal唤醒等待该条件的某个线程,pthread_cond_broadcast唤醒等待该条件的所有线程。

int pthread_cond_signal (pthread_cond_t *__cond);int pthread_cond_broadcast (pthread_cond_t *__cond)

示例如下:

#include 
#include
#include
#include
#include
#define DEBUG 1int num=0;pthread_mutex_t mylock=PTHREAD_MUTEX_INITIALIZER;pthread_cond_t qready=PTHREAD_COND_INITIALIZER;void * thread_func(void *arg){ int i=(int)arg; int ret; sleep(5-i);//线程睡眠,然最先生成的线程,最后苏醒 pthread_mutex_lock(&mylock);//调用pthread_cond_wait前,必须获得互斥锁 printf("thread %d is running \n",i); num++; pthread_mutex_unlock(&mylock);//解锁 pthread_cond_broadcast(&qready);//唤醒等待该条件的所有线程 return (void *)0;}int main(int argc, char** argv) { int i=0,err; pthread_t tid[4]; void *tret; for(;i<4;i++) { err=pthread_create(&tid[i],NULL,thread_func,(void *)i); if(err!=0) { printf("thread_create error:%s\n",strerror(err)); exit(-1); } } for (i = 0; i < 4; i++) { err = pthread_join(tid[i], &tret); if (err != 0) { printf("can not join with thread %d:%s\n", i,strerror(err)); exit(-1); } } return 0;}

4、用读写锁进行同步

读写锁也称为共享-独占(shared-exclusive)锁,允许多个线程同时读,只要没有写模式下的加锁,任意线程都可以进行读模式下的加锁;只能有一个线程同时写,只有读写锁处于不加锁状态时,才能进行写模式下的加锁。读写锁非常适合读数据的频率远大于写数据的频率从的应用中。到目前为止读写锁仍然不是属于POSIX标准。

(1) 读写锁初始化:  

#include
int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock, __const pthread_rwlockattr_t *__restrict __attr);int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock);

(2) 读/写加锁:

int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock)int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock)

(3) 读/写解锁:

int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock);

5、信号量、互斥锁、条件变量的区别

(1) 信号量和互斥锁的区别

        信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都在semtake的时候,就阻塞在哪里)。而互斥锁是用在多线程多任务互斥的,一个线程占用了某一个资源,那么别的线程就无法访问,直到这个线程unlock,其他的线程才开始可以利用这个资源。比如对全局变量的访问,有时要加锁,操作完了,在解锁。有的时候锁和信号量会同时使用的。也就是说,信号量不一定是锁定某一个资源,而是流程上的概念,比如:有A,B两个线程,B线程要等A线程完成某一任务以后再进行自己下面的步骤,这个任务并不一定是锁定某一资源,还可以是进行一些计算或者数据处理之类。而线程互斥量则是“锁住某一资源”的概念,在锁定期间内,其他线程无法对被保护的数据进行操作。在有些情况下两者可以互换。

(2) 何时互斥锁不够,还需要条件变量?

         假设有共享的资源sum,与之相关联的mutex 是lock_s。假设每个线程对sum的操作很简单的,与sum的状态无关,比如只是sum++。那么只用mutex足够了。程序员只要确保每个线程操作前,取得lock,然后sum++,再unlock即可。每个线程的代码将像这样:

add(){    pthread_mutex_lock(lock_s);    sum++;    pthread_mutex_unlock(lock_s);}

        如果操作比较复杂,假设线程t0,t1,t2的操作是sum++,而线程t3则是在sum到达100的时候,打印出一条信息,并对sum清零。这种情况下,如果只用mutex,则t3需要一个循环,每个循环里先取得lock_s,然后检查sum的状态。如果sum>=100,则打印并清零,然后unlock。如果sum >= 100,则unlock,并sleep()本线程合适的一段时间。

        这个时候,t0,t1,t2的代码不变,t3的代码如下:

print(){    while (1)    {        pthread_mutex_lock(lock_s);        if(sum<100)        {            printf(“sum reach 100!”);            pthread_mutex_unlock(lock_s);        }        else        {            pthread_mutex_unlock(lock_s);            my_thread_sleep(100);            return OK;        }    }}

这种办法有以下问题:

首先,sum在大多数情况下不会到达100,那么对t3的代码来说,大多数情况下,走的是else分支,只是lock和unlock,然后sleep(),这浪费了CPU处理时间。
其次,为了节省CPU处理时间,t3会在探测到sum没到达100的时候sleep()一段时间。这样却又带来另外一个问题,亦即t3响应速度下降。可能在sum到达200的时候,t4才会醒过来。
这样。程序员在设置sleep()时间的时候陷入两难境地,设置得太短了节省不了资源,太长了又降低响应速度.真是难办啊!

这个时候。condition variable内裤外穿,从天而降,拯救了焦头烂额的你。你首先定义一个condition variable:

pthread_cond_t cond_sum_ready=PTHREAD_COND_INITIALIZER;

t0,t1,t2的代码只要后面加两行,像这样:

add(){    pthread_mutex_lock(lock_s);    sum++;    pthread_mutex_unlock(lock_s);    if(sum>=100)        pthread_cond_signal(&cond_sum_ready);}

而t3的代码则是:

print{    pthread_mutex_lock(lock_s);    while(sum<100)    pthread_cond_wait(&cond_sum_ready, &lock_s);    printf(“sum is over 100!”);    sum=0;    pthread_mutex_unlock(lock_s);    return OK;}

注意两点:

1) 在thread_cond_wait()之前,必须先lock相关联的mutex, 因为假如目标条件未满足,pthread_cond_wait()实际上会unlock该mutex, 然后block,在目标条件满足后再重新lock该mutex, 然后返回。

2) 为什么是while(sum<100),而不是if(sum<100) ?这是因为在pthread_cond_signal()和pthread_cond_wait()返回之间,有时间差,假设在这个时间差内,还有另外一个线程t4又把sum减少到100以下了,那么t3在pthread_cond_wait()返回之后,显然应该再检查一遍sum的大小。这就是用 while的用意。

转载于:https://my.oschina.net/shou1156226/blog/757695

你可能感兴趣的文章
jquery的clone方法应用于textarea和select的bug修复不能copy值,clone id重复的解决
查看>>
无插件,直接加参数,chrome它可以模拟手机浏览器
查看>>
Android面试经验2
查看>>
IPC$命令详解
查看>>
Entity Framework 6 Recipes 2nd Edition(10-1)译->非Code Frist方式返回一个实体集合
查看>>
Atitit.软件开发的非功能性需求attilax 总结
查看>>
[LeetCode] Shortest Word Distance 最短单词距离
查看>>
JS转义 escape()、encodeURI()、encodeURIComponent()区别详解
查看>>
cocos2dx 编写shader 遇到 溢出问题
查看>>
OC与JS互相调用
查看>>
IT持续集成之质量管理
查看>>
用jquery追加的元素不能触发treeview事件
查看>>
java代码走查审查规范
查看>>
各大Oj平台介绍 刷题平台
查看>>
MyEclipse------如何连接MySQL
查看>>
如何利用脚本实现MySQL的快速部署以及一机多实例的部署
查看>>
uva 11270 - Tiling Dominoes(插头dp)
查看>>
[翻译] - <Entity Framework> - 直接执行数据库命令
查看>>
异常:System.BadImageFormatException,未能加载正确的程序集XXX
查看>>
Unity3D架构设计NavMesh寻路(未完待续)
查看>>