UNIX高级环境编程 第十一、12章 线程同步及属性

第十一、12章 线程及其控制

主要内容函数

  • 互斥量
    非递归互斥量
    递归互斥量spa

  • 读写锁线程

  • 条件变量rest

  • 自旋锁code

  • 屏障递归

互斥量

int pthread_mutex_init(pthread_mutex_t *restrict mutex,
                        const pthread_mutexattr_t *restrict attr);
//也能够把互斥量设置为常量PTHREAD_MUTEX_INITIALIZER(只适用于静态分配的互斥量)进行初始化。
int pthread_mutex_destroy(pthread_mutex_t *mutex);

int pthread_mutex_lock(pthread_mutex_t *mutex); 
int pthread_mutex_trylock(pthread_mutex_t *mutex);
//若是互斥量处于未锁住状态,则锁住互斥量,不然返回EBUSY。
int pthread_mutex_unlock(pthread_mutex_t *mutex);

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

pthread_mutex_timedlock容许绑定线程阻塞时间,若是超过设定的时间点,pthread_mutex_timedlock不会对互斥量进行加锁,而是返回错误码ETIMEDOUT, 注意tsptr表示的是某个时间点,而不是一段时间长度接口

产生死锁的四个条件进程

  • 互斥条件:一个资源每次只能被一个进程使用ip

  • 请求与保持条件:一个进程因请求资源而阻塞时,对已得到的互斥资源保持不放内存

  • 不剥夺条件:进程已得到的资源,在末使用完以前,不能强行剥夺

  • 循环等待条件:若干进程之间造成一种头尾相接的循环等待资源关系

预防死锁的几个方法:

  • 对于每一个进程,将其须要的全部资源一次性分配,若失败,系统收回其保持的全部资源(对应第二个条件)

  • 每一个进程或线程申请资源时,按照相同的顺序(对应第四个条件)

互斥量属性

主要内容

  • 进程共享属性

    PTHREAD_PROCESS_PRIVATE (默认)
    PTHREAD_PROCESS_SHARED

  • 健壮属性

    PTHREAD_MUTEX_STALLED (默认)
    PTHREAD_MUTEX_ROBUST

  • 类型属性
    PTHREAD_MUTEX_NORMAL 默认
    PTHREAD_MUTEX_ERRORCHECK
    PTHREAD_MUTEX_RECURSIVE (递归锁)
    PTHREAD_MUTEX_DEFAULT

int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr, int *restrict pshared);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,int pshared);

pshared能够设置为两个值:PTHREAD_PROCESS_PRIVATE(默认),PTHREAD_PROCESS_SHARED
(从多个进程彼此之间共享的内存数据块中分配的互斥量就能够用于这些线程的同步)

int pthread_mutexattr_getrobust(const pthread_mutexattr_t *restrict attr,int *restrict robust);
int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr,int robust);

PTHREAD_MUTEX_STALLED: 持有互斥量的进程终止时不须要采起特别的动做;

PTHREAD_MUTEX_ROBUST: 当进程P1的T1线程或其余Pi进程持有锁且终止时没有释放锁时,P1中的T2线程此时利用
ptread_mutex_lock 函数获取锁时, T2线程不会阻塞且成功获取锁,但返回的值是EOWNERDEAD而不是0

注意: 当同一个进程内,若是一个线程退出时没有释放非健壮性锁,那么其余的线程会被阻塞,而不是返回错误!!!

int pthread_mutex_consistent(pthread_mutex_t *mutex);

pthread_mutex_lock返回EOWNERDEAD时,须要调用 pthread_mutex_consistent 函数来清除这种状态

int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr,int *restrict type);
int pthread_mutexattr_settype(pthread_mutexattr_t *attr,int type);

四种类型

clipboard.png
                       [Figure 0]

  • 情景一

使用递归锁每每不是一个好主意,特别是和条件变量一块儿使用时。以下图所示,若线程A在第a步以前已经对mutex上锁
那么第b.1步并无真正解锁,当执行到b.2时,线程A休眠等待线程B的信号,可是线程B第a步没法获取mutex,则产生了死锁

clipboard.png

                       [Figure 1]

  • 情景二
    若mutex不是递归锁,当func1调用func2时,显然会产生死锁。

clipboard.png

                       [Figure 2]
在不利用递归锁状况下,能够采起以下方法避免死锁:  
1.修改func2接口,指示mutex是否已经被调用者func1锁定,当锁定时,显然无须再次上锁.
2.生成一个func2_locked函数,相比func2, func2_locked无须第a步和第c步,而后,将func1和func2的第b步替换为func2_locked函数

读写锁

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
                        const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrwrock(pthread_rwlock_t *rwlock);

当读写锁是写加锁状态时,在这个锁被解锁以前,全部试图对这个所加锁的线程都会被阻塞。
当读写锁是读加锁状态时,全部试图以读模式对它进行加锁的线程均可以获得访问权,
可是任何但愿以写模式对此进行加锁的线程都会阻塞,直到全部的线程释放它们的读锁为止

读写锁属性

读写锁的惟一属性是进程共享属性

int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);

int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *restrict attr,
                                  int *restrict pshared);
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr,int pshared);

条件变量

创建在互斥量上的同步: 先来先得(FCFS),先获取锁的线程或进程解锁时,唤醒阻塞的相关线程或进程
创建在条件变量上的同步:人为设定前后执行关系,如Figure 1所示,线程A的执行取决于线程B的唤醒

int pthread_cond_init(pthread_cond_t *restrict cond,
                       const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);

int pthread_cond_wait(pthread_cond_t *restrict cond, 
                        pthread_mutex_t *restrict mutex);
                        
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
                            pthread_mutex_t *restrict mutex,
                              const struct timespec *restrict tsptr);
    若是超过到期时条件仍是没有出现,则函数从新获取互斥量,而后返回ETIMEDOUT

int pthread_cond_signal(pthread_cond_t *cond);
    至少能唤醒一个等待该条件的线程,
int pthread_cond_broadcast(pthread_cond_t *cond);
    能唤醒等待该条件的全部线程。

代码展现:                
注意 “while(workq == NULL)” 的做用很是重要:
1)是否能够用 if 取代 while :
若条件变量qready只是和变量workq对应,那么能够替换。若qready还和其余变量(好比 workq2)对应,显然不行,
由于线程被唤醒时便跳出if语句,继续执行。可是这个线程被唤醒的缘由多是另外一个线程修改了workq2后调用pthread_cond_signal.
2)若条件变量qready只是和变量workq对应,那么“while(workq == NULL)”是否能够删除:
绝对不能,考虑若enqueue_msg先被一个线程执行完毕(但此时没有线程被唤醒),接着另一个线程执行缺乏“while(workq == NULL)”语句的process_msg函数时就会产生死锁。
clipboard.png

-------------------------------------------[Figure 3]----------------------------------------------

自旋锁

自旋锁与互斥量相似,但它不是经过休眠使进程阻塞,而是在获取锁以前一直处于忙等(自旋)阻塞状态。
自旋锁可用于如下状况:锁被持有的时间短,并且线程并不但愿在从新调度上花费太多的成本。

int pthread_spin_init(pthread_spinlock_t *lock,int pshared);
int pthread_spin_destroy(pthread_spinlock_t *lock);

int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_trylock(pthread_spinlock_t *lock);
    若没法获取锁,当即返回EBUSY
int pthread_spin_unlock(pthread_spinlock_t *lock);

屏障

屏障是用户协调多个线程并行工做的同步机制。屏障容许每一个线程阻塞,直到全部相关线程到达一点

int pthread_barrier_init(pthread_barrier_t *restrict barrier,
                            const pthread_barrierattr_t *restrict attr,
                                unsigned int count);
    最多有count - 1个线程阻塞
int pthread_barrier_destroy(pthread_barrier_t *barrier);
int pthread_barrier_wait(pthread_barrier_t *barrier);

屏障属性

屏障属性只有进程共享属性

int pthread_barrierattr_init(pthread_barrierattr_t *attr);
int pthread_barrierattr_destroy(pthread_barrierattr_t *attr);

int pthread_barrierattr_getpshared(const pthread_barrierattr_t *restrict attr,
                                   int *restrict pshared);
int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr,int pshared)
相关文章
相关标签/搜索