pthread中互斥量,锁和条件变量

互斥量

#include <pthread.h>

pthread_mutex_t mutex=PTHREAD_MUTEX_INTIIALIZER;
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);

注意:

  1. 不能拷贝互斥量,可以拷贝指向互斥量的指针,这样可以使多个线程或函数共享互斥量来同步
  2. 应该在函数体外生命互斥量,若没有外部文件使用,就声明为静态类型;若有其他文件使用,就声明为外部类型
  3. 使用malloc分配一个包含互斥量的数据结构时,用pthread_init_mutex来初始化,用...destory销毁
  4. 将互斥量与要保护的数据联系在一起(定义在一个结构体中)
  5. 当没有线程在乎斥量上阻塞时,立即释放。在刚解锁互斥量的线程内若以后不再使用释放
  6. 互斥量较少时程序运行的较快,所以互斥量保护的临界区应该较大
  7. 如互斥量保护的代码包含无关的片段,应该把互斥量分解为几个较小的互斥量来提高性能
  8. 多线程同时访问队列时使用两个互斥量:一个保护队头,一个队列元素内的数据
  9. 多线程同时访问树形结构时,应为每个节点建立个互斥量

互斥锁

#include <pthread.h>

int pthread_mutex_tlock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthreadd_mutex_t *mutex);

互斥锁属性

//获得/修改共享互斥量属性
pthread_mutexattr_t attr;  
int pthread_mutexattr_init(pthread_mutexattr_t *attr);  
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);  
int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr,int *pshared);  
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,int pshared);

pshared的取值

  1. THREAD_PROCESS_SHARED:那么由这个属性对象创建的互斥锁将被保存在共享内存中,可以被多个进程中的线程共享。
  2. PTHREAD_PROCESS_PRIVATE:那么只有和创建这个互斥锁的线程在同一个进程中的线程才能访问这个互斥锁。

互斥锁类型

//获得/修改类型互斥量属性
int pthread_mutexattr_settype(pthread_mutexattr_t *attr,int kind);  
int pthread_mutexattr_gettype(pthread_mutexattr_t *attr,int *kind);
  1. PTHREAD_MUTEX_NORMAL,不进行deadlock detection(死锁检测)。企图进行relock这个mutex会导致deadlock.如果一个线程对未加锁的或已经unlock的mutex对象进行unlock操作,结果是不未知的。
  2. PTHREAD_MUTEX_ERRORCHECK,那么将进行错误检查。如果一个线程企图对一个已经锁住的mutex进行relock,将返回一个错误。如果一个线程对未加锁的或已经unlock的mutex对象进行unlock操作,将返回一个错误。
  3. PTHREAD_MUTEX_RECURSIVE,mutex会有一个锁住次数(lock count)的概念。当一个线程成功地第一次锁住一个mutex的时候,锁住次数(lock count)被设置为1,每一次一个线程unlock这个mutex的时候,锁住次数(lock count)就减1。当锁住次数(lock count)减少为0的时候,其他线程就能获得该mutex锁了。如果一个线程对未加锁的或已经unlock的mutex对象进行unlock操作,将返回一个错误,如果一个线程对这种类型的互斥锁重复上锁,不会引起死锁,一个线程对这类互斥锁的多次重复上锁必须由这个线程来重复相同数量的解锁,这样才能解开这个互斥锁,别的线程才能得到这个互斥锁。如果试图解锁一个由别的线程锁定的互斥锁将会返回一个错误代码。如果一个线程试图解锁已经被解锁的互斥锁也将会返回一个错误代码。这种类型的互斥锁只能是进程私有的(作用域属性为PTHREAD_PROCESS_PRIVATE)。
  4. PTHREAD_MUTEX_DEFAULT,企图递归的获取这个mutex的锁的结果是不确定的。unlock一个不是被调用线程锁住的mutex的结果也是不确定的。企图unlock一个未被锁住的mutex导致不确定的结果。

互斥锁协议属性

int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol);  
int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol);  
  1. PTHREAD_PRIO_NONE:线程的优先级和调度不会受到互斥锁拥有权的影响。
  2. PTHREAD_PRIO_INHERIT:当高优先级的等待低优先级的线程锁定互斥量时,低优先级的线程以高优先级线程的优先级运行。这种方式将以继承的形式传递。当线程解锁互斥量时,线程的优先级自动被将到它原来的优先级。(“优先级继承”意味着,当一个线程在由另一个低优先级线程拥有的互斥量上等待时,后者的优先级将被增加到等待线程的优先级.)
  3. PTHREAD_PRIO_PROTECT:拥有该类型的互斥量的线程将以自己的优先级和它拥有的互斥量的线程将以自己的优先级和它拥有的互斥量的优先级较高者运行,其他等待该线程拥有的锁得线程对该线程的调度优先级没有影响。

  PTHREAD_PRIO_INHERIT 和 PTHREAD_PRIO_PROTECT 只有在采用实时调度策略SCHED_FIFO 或SCHED_RR的优先级进程内可用。

  一个线程可以同时拥有多个混合使用PTHREAD_PRIO_INHERIT 和PTHREAD_PRIO_PROTECT协议属性初始化的互斥锁。在这种情况下,该线程将以通过其中任一协议获取的最高优先级执行。pthread_mutexattr_getprotocol可用来获取互斥锁属性对象的协议属性。

互斥锁对象优先级属性

int pthread_mutexattr_setprioceiling(pthread_mutexatt_t *attr, int prioceiling, int *oldceiling);  
int pthread_mutexattr_getprioceiling(const pthread_mutexatt_t *attr, int *prioceiling);

  prioceiling指定已初始化互斥锁的优先级上限。优先级上限定义执行互斥锁保护的临界段时的最低优先级。prioceiling 位于SCHED_FIFO 所定义的优先级的最大范围内。要避免优先级倒置,请将prioceiling 设置为高于或等于可能会锁定特定互斥锁的所有线程的最高优先级。oldceiling 用于返回以前的优先级上限值。
  pthread_mutex_setprioceiling可更改互斥锁mutex的优先级上限prioceiling。
  pthread_mutex_setprioceiling可锁定互斥锁(如果未锁定的话),或者一直处于阻塞状态,直到它成功锁定该互斥锁,更改该互斥锁的优先级上限并将该互斥锁释放为止。锁定互斥锁的过程无需遵循优先级保护协议。
  如果 pthread_mutex_setprioceiling成功,则将在 old_ceiling 中返回以前的优先级上限值。如果pthread_mutex_setprioceiling失败,则互斥锁的优先级上限保持不变。pthread_mutex_getprioceiling会返回mutex 的优先级上限prioceiling。

  注意:“优先级上限”协议意味着当一个线程拥有互斥量时,它将以指定的优先级运行。

互斥锁的强健属性

int pthread_mutexattr_setrobust_np(pthread_mutexattr_t *attr, int *robustness);  
int pthread_mutexattr_getrobust_np(const pthread_mutexattr_t *attr, int *robustness);

  robustness 定义在互斥锁的持有者“死亡”时的行为。pthread.h 中定义的robustness 的值为PTHREAD_MUTEX_ROBUST_NP 或 PTHREAD_MUTEX_STALLED_NP。缺省值为PTHREAD_MUTEX_STALLED_NP。

  1. PTHREAD_MUTEX_STALLED_NP: 如果互斥锁的持有者死亡,则以后对pthread_mutex_lock() 的所有调用将以不确定的方式被阻塞。
  2. PTHREAD_MUTEX_ROBUST_NP: 如果互斥锁的持有者“死亡”了,或者持有这样的互斥锁的进程unmap了互斥锁所在的共享内存或者持有这样的互斥锁的进程执行了exec调用,则会解除锁定该互斥锁。互斥锁的下一个持有者将获取该互斥锁,并返回错误EOWNWERDEAD。

  如果互斥锁具有PTHREAD_MUTEX_ROBUST_NP的属性,则应用程序在获取该锁时必须检查pthread_mutex_lock 的返回代码看获取锁时是否返回了EOWNWERDEAD错误。如果是,则

  1. 互斥锁的新的持有者应使该互斥锁所保护的状态保持一致。因为互斥锁的上一个持有者“死亡”时互斥锁所保护的状态可能出于不一致的状态。
  2. 如果互斥锁的新的持有者能够使该状态保持一致,请针对该互斥锁调用pthread_mutex_consistent_np(),并解除锁定该互斥锁。
  3. 如果互斥锁的新的持有者无法使该状态保持一致,请勿针对该互斥锁调用pthread_mutex_consistent_np(),而是解除锁定该互斥锁。所有等待的线程都将被唤醒,以后对pthread_mutex_lock() 的所有调用都将无法获取该互斥锁。返回错误为ENOTRECOVERABLE。

     如果一个线程获取了互斥锁,但是获取时得到了EOWNERDEAD的错误,然后它终止并且没有释放互斥锁 ,则下一个持有者获取该锁时将返回代码EOWNERDEAD。

避免死锁

  该函数允许线程阻塞特定时间,如果加锁失败就会返回ETIMEDOUT

#include <pthread.h>
#include <time.h>

int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timesec *restrict tsptr);

互斥锁的优先级

#include <pthread.h>
int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol);

  attr 指示以前调用 pthread_mutexattr_init() 时创建的互斥锁属性对象。protocol 可定义应用于互斥锁属性对象的协议。

  pthread.h 中定义的 protocol 可以是以下值之一:PTHREAD_PRIO_NONEPTHREAD_PRIO_INHERIT 或 PTHREAD_PRIO_PROTECT

  1. PTHREAD_PRIO_NONE线程的优先级和调度不会受到互斥锁拥有权的影响。
  2. PTHREAD_PRIO_INHERIT,当高优先级的等待低优先级的线程锁定互斥量时,低优先级的线程以高优先级线程的优先级运行。这种方式将以继承的形式传递。当线程解锁互斥量时,线程的优先级自动被将到它原来的优先级。(“优先级继承”意味着,当一个线程在由另一个低优先级线程拥有的互斥量上等待时,后者的优先级将被增加到等待线程的优先级.),此协议值(如 thrd1)会影响线程的优先级和调度。如果更高优先级的线程因 thrd1 所拥有的一个或多个互斥锁而被阻塞,而这些互斥锁是用 PTHREAD_PRIO_INHERIT 初始化的,则 thrd1 将以高于它的优先级或者所有正在等待这些互斥锁(这些互斥锁是 thrd1指所拥有的互斥锁)的线程的最高优先级运行。

    如果 thrd1 因另一个线程 (thrd3) 拥有的互斥锁而被阻塞,则相同的优先级继承效应会以递归方式传播给 thrd3

    使用 PTHREAD_PRIO_INHERIT 可以避免优先级倒置。低优先级的线程持有较高优先级线程所需的锁时,便会发生优先级倒置。只有在较低优先级的线程释放该锁之后,较高优先级的线程才能继续使用该锁。设置 PTHREAD_PRIO_INHERIT,以便按与预期的优先级相反的优先级处理每个线程。

    如果为使用协议属性值 PTHREAD_PRIO_INHERIT 初始化的互斥锁定义了 _POSIX_THREAD_PRIO_INHERIT,则互斥锁的属主失败时会执行以下操作。属主失败时的行为取决于 pthread_mutexattr_setrobust_np() 的 robustness 参数的值,1.解除锁定互斥锁。2.互斥锁的下一个属主将获取该互斥锁,并返回错误 EOWNERDEAD。3.互斥锁的下一个属主会尝试使该互斥锁所保护的状态一致。如果上一个属主失败,则状态可能会不一致。如果属主成功使状态保持一致,则可针对该互斥锁调用 pthread_mutex_init() 并解除锁定该互斥锁。注:1.如果针对以前初始化的但尚未销毁的互斥锁调用 pthread_mutex_init(),则该互斥锁不会重新初始化。2.如果属主无法使状态保持一致,请勿调用 pthread_mutex_init(),而是解除锁定该互斥锁。在这种情况下,所有等待的线程都将被唤醒。以后对 pthread_mutex_lock() 的所有调用将无法获取互斥锁,并将返回错误代码 ENOTRECOVERABLE。现在,通过调用 pthread_mutex_destroy() 来取消初始化该互斥锁,即可使其状态保持一致。调用 pthread_mutex_init() 可重新初始化互斥锁。3.如果已获取该锁的线程失败并返回 EOWNERDEAD,则下一个属主将获取该锁及错误代码 EOWNERDEAD

  3. PTHREAD_PRIO_PROTECT,当线程拥有一个或多个使用 PTHREAD_PRIO_PROTECT 初始化的互斥锁时,此协议值会影响其他线程(如 thrd2)的优先级和调度。thrd2 以其较高的优先级或者以 thrd2 拥有的所有互斥锁的最高优先级上限运行。基于被 thrd2 拥有的任一互斥锁阻塞的较高优先级线程对于 thrd2 的调度没有任何影响。
    • 有该类型的互斥量的线程将以自己的优先级和它拥有的互斥量的线程将以自己的优先级和它拥有的互斥量的优先级较高者运行,其他等待该线程拥有的锁得线程对该线程的调度优先级没有影响,如果某个线程调用 sched_setparam() 来更改初始优先级,则调度程序不会采用新优先级将该线程移到调度队列末尾。
    • 线程拥有使用 PTHREAD_PRIO_INHERIT 或 PTHREAD_PRIO_PROTECT 初始化的互斥锁
    • 线程解除锁定使用 PTHREAD_PRIO_INHERIT 或 PTHREAD_PRIO_PROTECT 初始化的互斥锁

注意:一个线程可以同时拥有多个混合使用 PTHREAD_PRIO_INHERIT 和 PTHREAD_PRIO_PROTECT 初始化的互斥锁。在这种情况下,该线程将以通过其中任一协议获取的最高优先级执行PTHREAD_PRIO_INHERIT 和 PTHREAD_PRIO_PROTECT 只有在采用实时调度策略SCHED_FIFO 或SCHED_RR的优先级进程内可用

注意:

  1. pthread_mutex_trylock会尝试对互斥量加锁,如果该互斥量已经被锁住,函数调用失败,返回EBUSY,否则加锁成功返回0,线程不会被阻塞。
  2. 当调用线程使用pthread_mutex_lock加锁互斥量时,若互斥量被锁住,调用线程阻塞
  3. 如果调用线程将互斥量锁住,不能再加锁该互斥量,这样做会反悔错误EDEADLK,或陷入死锁
  4. 原子性:当多个线程运行在多个处理器上,其他线程不会发现被破坏的不变量
  5. 固定加锁层次:当数据上需要使用两个独立的互斥量时,应该先加锁互斥量A再加锁互斥量B,平衡或修剪树时使用层次锁。
  6. 试加锁和回退:锁住某个集合中的第一个互斥量时用pthread_mutex_trylock来加锁集合中的其他互斥量,如果失败将集合中的以加锁互斥量释放
  7. 若使用试加锁和回退和回退算法,应该以与加锁相反的方向解锁互斥量,有利于减少回退操作性的可能
  8. 链锁:两个锁的作用范围相互交叠。当锁住一个互斥量后进入一个代码区,该区域需要另个互斥量,当锁住另个互斥量后第一个互斥量不再需要,就可以释放(用作遍历树形结构或链表,为每个节点创建一个互斥量,首先锁住队头或根节点,然后找到期望的节点锁住他,然后释放根节点或队头互斥量);搜索某个节点时使用链锁(多个线程活跃在层次的不同部分时)。
  9. POSIX线程锁机制的Linux实现都不是取消点,因此,延迟取消类型的线程不会因收到取消信号而离开加锁等待。
  10. 线程在加锁后解锁前被取消,锁将永远保持锁定状态。因此如果在关键区段内有取消点存在,或者设置了异步取消类型,则必须在退出回调函数中解锁。
  11. 锁机制不是异步信号安全的,也就是说,不应该在信号处理过程中使用互斥锁,否则容易造成死锁。

 条件变量

#include <pthread.h>
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *condattr);
int pthread_cond_destroy(pthread_cond_t *cond);
  1. 条件变量总是返回锁住的互斥量,允许使用队列的线程之间交换队列状态的信息机制
  2. 条件变量与互斥量相关,也于互斥量保护的共享数据相关的信号机制
  3. 在一个条件变量上等待会导致一下院子操作:释放相关的互斥量,等待其他线程发送给该条件变量信号(唤醒一个等待者)或广播该条件变量(唤醒所有等待者),等待条件变量时互斥量必须始终锁住,当线程从条件变量等待中醒来时,继续锁住互斥量(即:阻塞线程前,条件变量等待操作将解锁互斥量,重新返回线程前,会再次锁住互斥量)
  4. 条件变量的作用是发信号而不是互斥
  5. 互斥量不仅要与条件变量一起使用,还要单独使用(不能将互斥量作为条件变量的一部分创建);一个互斥量与多个条件变量相关(如:队列可以为空,也可以为满,设置两个条件变量让线程等待不同的条件,但只有一个互斥量来协调对队列头的访问)
  6. 一个条件变量应该与一个谓词相关
  7. 信号比广播有效(条件变量和谓词都是程序中的共享数据,他们被多个线程使用,可能同时使用,他们被相同的互斥量锁住,在没有锁住互斥量之前就发信号或广播条件变量似乎有可能的,更安全的方式是先锁住互斥量)
  8. 不能拷贝条件变量但可以传递条件变量的指针使不同函数和线程使用它来同步
  9. 若有其他文件需要使用该条件变量则声明为extern类型否则声明为static
  10. 可以将条件变量,互斥量和谓词声明在一个结构体中
  11. 在广播了该条件变量并唤醒了所有等待线程的线程内,确定不再有线程使用可释放该条件变量
  12. 线程从列表中删除了一个包含该条件变量的节点后,广播所有等待该条件变量的线程,此时释放条件变量是安全的
  13. 并发的等待同一个条件变量的线程必须制定同一个相关的互斥量,任何条件变量在特定时刻只能与一个互斥量相关联,互斥量可以与多个条件变量相关联
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex,struct timespec *expiration);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
  1. 在锁住相关的互斥量之后和等待条件变量之前要测试谓词,如果线程发信号或广播一个条件变量时而没有线程等待该条件变量,则什么也没有发生,若在这之后有线程调用pthread_cond_wait,则将一直等待下去无视刚才广播的事实,这意味该线程永远不能被唤醒,因为在线程等待条件变量之前互斥量一直被锁住
  2. 因该在循环中等待条件变,来避免程序错误,处理机竞争和假唤醒
  3. 被拦截的唤醒:线程执行时异步的,从条件变量等待中唤醒包括加锁相应的互斥量。也就是说可能有多个线程被唤醒(被pthread_cond_broadcast唤醒),被唤醒的线程都“争着”去处理共享数据,但只有一个线程能处理到这个共享数据,等它处理完毕后,其他线程也会进入该临界区去处理共享数据,这个时候就会出现共享数据被多次处理的情况,我们的解决方法是在被唤醒后,在去检查一下谓词变量,看该共享数据是否已经被处理了。
  4. 松散的谓词:有时候谓词表示了“可能有工作”而不是“有工作”的意思。所以,当线程被唤醒,我们必须确认到底有没有工作。
  5. 假唤醒:在有些系统中,我们没有用pthread_cond_signal()或pthread_cond_broadcast()来唤醒用pthread_cond_wait()休眠的线程,但是在休眠的线程还是会被唤醒,这是怎么回事呢?在Linux中,被休眠的进程或线程,都有被信号(linux中的信号)打断的可能,也就是说,如果线程或进程在休眠中,会有被唤醒的可能,所以我们在有可能引起休眠的API调用返回后都会检查一下返回值是否为EINTR,如果是,那么线程或进程都将继续休眠。
  6. tiemdwait函数等待某个时间结束后会返回ETIMEOUT状态,时间是绝对时间。处理该错误之前要先检测谓词,若等待条件为真,那么等待长时间就不重要了。
  7. 不能用发信号代替广播,使用广播时因为等待线程会处理被拦截的唤醒,发信号与广播真正的区别是效率:广播唤醒额外的线程,这些线程检测到自己的谓词继续等待,不能用发信号代替广播
  8. 当有个线程需要被唤醒来处理改变后的状态用发信号,如果多个谓词条件使用同一个条件变量,则不能是使用发信号,也不能用重发信号,如果向队列中增加一个元素,而且只有等待钙元素的线程在条件变量上阻塞,则可使用发信号,让其他线程继续等待,如果增加多个元素,可能要使用广播。

恰当的使用signal和wait可参考:https://blog.csdn.net/u011418878/article/details/69374972

条件变量的属性

#include < pthread.h >

int pthread_condattr_init(pthread_condattr_t * attr );
int pthread_condattr_destroy(pthread_condattr_t * attr );

#ifdef _POSIX_THREAD_PROCESS_SHARED
int pthread_condattr_getpshared(pthread_condattr_t *attr,int *pshared);
int pthread_condattr_setpshared(pthread_condattr_t *attr,int *pshared);
#endif // _POSIX_THREAD_PROCESS_SHARED
  1. pthread_condattr_destroy()函数应销毁条件变量属性对象; 实际上,对象变得未初始化。实现可能导致pthread_condattr_destroy()将attr引用的对象设置为无效值。可以使用pthread_condattr_init()重新初始化已销毁的attr属性对象; 在销毁之后引用对象的结果是未定义的。
  2. pthread_condattr_init()函数将初始化条件变量属性对象ATTR与所有实现中定义的属性的缺省值。
  3. 如果调用pthread_condattr_init()指定已初始化的attr属性对象,则结果未定义。
  4. 在使用条件变量属性对象初始化一个或多个条件变量之后,影响属性对象的任何函数(包括破坏)都不会影响任何先前初始化的条件变量。
  5. cattr 的数据类型为 opaque,其中包含一个由系统分配的属性对象。cattr 范围可能的值为 PTHREAD_PROCESS_PRIVATE 和 PTHREAD_PROCESS_SHAREDPTHREAD_PROCESS_PRIVATE 是缺省值。

    条件变量属性必须首先由 pthread_condattr_destroy 重新初始化后才能重用。pthread_condattr_init() 调用会返回指向类型为 opaque 的对象的指针。如果未销毁该对象,则会导致内存泄漏。

  6. 这两个函数执行成功都返回0,返回其他值都是错误
  7. 为使用一个PTHREAD_PROCESS_SHARED条件变量,必须使用一个PTHREAD_PROCESS_SHARED互斥量,因为同步使用一个条件变量的两个线程必须使用一样的互斥量,等待一个条件变量会自动解锁然后加锁相关的互斥量,因此如果互斥量没有与PTHREAD_PROCESS_SHARED一起被创建,同步不会工作。

条件变量的范围

pthread_condattr_t cattr;
int    pthread_condattr_setpshared(pthread_condattr_t *cattr, int pshared);//设置条件变量的范围
/* all processes */
ret = pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
/* within a process */
ret = pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_PRIVATE);

int    pthread_condattr_getpshared(const pthread_condattr_t *cattr,int *pshared);//获取条件变量的范围
//以上两个函数成功都返回0,返回其它任何值都失败

  pshared 属性在共享内存中设置为 PTHREAD_PROCESS_SHARED,则其所创建的条件变量可以在多个进程中的线程之间共享。此行为与最初的 Solaris 线程实现中 mutex_init() 中的 USYNC_PROCESS 标志等效。如果互斥锁的 pshared 属性设置为 PTHREAD_PROCESS_PRIVATE,则仅有那些由同一个进程创建的线程才能够处理该互斥锁。PTHREAD_PROCESS_PRIVATE 是缺省值。PTHREAD_PROCESS_PRIVATE 所产生的行为与在最初的 Solaris 线程的 cond_init() 调用中使用 USYNC_THREAD 标志相同。PTHREAD_PROCESS_PRIVATE 的行为与局部条件变量相同。PTHREAD_PROCESS_SHARED 的行为与全局条件变量等效。

 

转载于:https://www.cnblogs.com/tianzeng/p/9157927.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值