Linux/UNIX线程(2)

线程(2)

线程同步

当多个控制线程共享同样内存时,须要确保每一个线程看到一致的数据视图。假设每一个线程使用的变量都是其它线程不会读取或改动的,那么就不在一致性问题。

当两个或多个线程试图在同一时间改动同一变量时,也须要进行同步。考虑变量递增操作的情况:增量操作通常分三步:

1.      从内存单元读入寄存器

2.      在寄存器中进行变量值的添加

3.      把新的值写回内存单元

相互排斥量

能够通过使用pthread的相互排斥接口保护数据,确保同一时间仅仅有一个线程訪问数据。相互排斥量从本质上说是一把锁,在訪问资源前对相互排斥量加锁,在訪问完毕后释放相互排斥量上的锁。

对相互排斥量进行加锁以后,不论什么其它试图再次对相互排斥量加锁的线程将会被堵塞直到线程释放该相互排斥锁。

相互排斥变量用pthread_mutex_t数据类型来表示。在使用相互排斥量曾经。必须首先对其进行初始化。能够把它置为PTHREAD_MUTEX_INITIALIZER(仅仅对静态分配的相互排斥量),也能够通过调用pthread_mutex_init函数进行初始化。假设动态分配相互排斥量。那么释放内存前须要调用pthread_mutex_destroy。

用默认属性初始化相互排斥量,仅仅须要把attr设置为NULL

#include <pthread.h>

int pthread_mutex_init(pthread_mutex_t *restrict mutex,constpthread_mutexattr_t *restrict attr);
  intpthread_mutex_destroy(pthread_mutex_t *mutex);

若成功返回0,错误返回错误编号。

对相互排斥量进行加锁,须要调用pthread_mutex_lock,假设相互排斥量已经上锁,调用线程将堵塞直到相互排斥量被解锁。

#include <pthread.h>

int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_trylock( pthread_mutex_t *mutex );

int pthread_mutex_unlock(pthread_mutex_t *mutex);

若成功返回0,错误返回错误编号。

假设线程不希望不堵塞,它能够使用pthread_mutex_trylock尝试对相互排斥量进行加锁。假设调用pthread_mutex_trylock时相互排斥量处于未锁住状态。那么pthread_mutex_trylock将锁住相互排斥量,不会出现堵塞并返回0。否则pthread_mutex_trylock就会失败。不能锁住相互排斥量。而返回EBUSY

避免死锁

假设线程试图对同一个相互排斥量加锁两次,那么它自身就会陷入死锁状态。

假设程序中使用多个相互排斥量时,假设同意一个线程一直占有第一个相互排斥量,而且试图锁住第二个相互排斥量时处于堵塞状态。可是游泳第二个相互排斥量的线程也试图锁住第一个相互排斥量,这是就会发生死锁。

能够通过小心地控制相互排斥量加锁的顺序来避免死锁的发生。仅仅有一个线程试图以与还有一个线程相反的顺序锁住相互排斥量时,才可能出现死锁。

读写锁

读写锁有三种状态:度模式下加锁状态。写模式下加锁状态,不加锁状态。一次仅仅有一个线程能够占用写模式的读写锁。可是多个线程能够同一时候占用读模式的读写锁。

读写锁很适合于对数据结构读的次数远大于写的情况。读写锁也叫做共享——独占锁。当读写锁以读模式锁住时,它是以共享模式锁住的;当它以写模式锁住时,它是以独占模式锁住的。

与相互排斥量一样,读写锁在使用之前必须初始化。在释放它们底层的内存前必须销毁。

#include <pthread.h>

intpthread_rwlock_init(pthread_rwlock* restrict rwlock, const pthread_rwlockattr_t* restrict attr);

int pthread_rwlock_destroy(pthread_rwlock_t* rwlock);

要在读模式下锁定读写锁,须要调用pthread_rwlock_rdlock;要在写模式下锁定读写锁。须要调用pthread_rwlock_wrlock。无论以何种方式锁住读写锁。都能够调用pthreead_rwlock_unlock进行解锁。

#include <pthread.h>

intpthread_rwlock_rdlock(pthread_rwlock_t* rwlock);

int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);

int pthread_rwlock_unlock(pthread_rwlock_t* rwlock);

全部的返回值都是:若成功则返回0,否则返回错误编号

#include <pthread.h>

int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock);

int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock);

条件变量

条件变量是线程可用的还有一种同步机制。

条件变量给多线程提供了一个回合的场所。条件变量与相互排斥量一起使用时,同意线程以无竞争的方式等待特定的条件发生。

条件本身是由相互排斥量保护的。

线程在改变条件状态前必须首先锁住相互排斥量。其它线程在获得相互排斥量之前不会觉察到这样的改变。由于必须锁定相互排斥量以后才干计算条件。

条件变量使用之前必须首先进行初始化,pthread_cond_t数据类型代表的条件变量以两种方式进行初始化。能够把常量PTHREAD_COND_INITIALIZER赋给静态分配的条件变量,可是假设条件变量时动态分配的,能够使用pthread_cond_init函数进行初始化。

在释放底层的内存空间之前。能够使用pthread_cond_destroy函数对条件变量进行去初始化。

#include <pthread.h>

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

int pthread_cond_destroy (pthread_cond_t* cond); 

除非须要创建一个非默认属性的条件变量,否则pthread_cond_init函数的attr參数能够设置NULL

使用pthread_cond_wait等待条件变为真,假设在给定时间内条件不能满足,那么会生成一个代表出错误码的返回值。

intpthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)

intpthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, conststruct timespec *abstime)

条件等待pthread_cond_wait()和计时等待pthread_cond_timedwait(),当中计时等待方式假设在给定时刻前条件没有满足。则返回ETIMEOUT。结束等待,当中abstime以与time()系统调用相允许义的绝对时间形式出现。0表示格林尼治时间1970年1月1日0时0分0秒。

不管哪种等待方式。都必须和一个相互排斥锁配合。以防止多个线程同一时候请求pthread_cond_wait()(或pthread_cond_timedwait()。下同)的竞争条件(RaceCondition)。

mutex相互排斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或者适应锁(PTHREAD_MUTEX_ADAPTIVE_NP),且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列曾经,mutex保持锁定状态,并在线程挂起进入等待前解锁。在条件满足从而离开pthread_cond_wait()之前,mutex将被又一次加锁,以与进入pthread_cond_wait()前的加锁动作相应。

原文地址:https://www.cnblogs.com/zfyouxi/p/5368824.html