####### 线程同步
当多个控制线程共享相同的内存时,需要确保每个线程看到一致的数据视图。
如果使用的变量都是其他线程不会读取和修改的,那么就不会存在一致性问题。但是,当一个线程可以修改的变量,其他线程也可以读取或者修改时,就需要对这些线程进行同步,确保它们在访问变量的存储内容时不会访问到不一致的值。
当一个线程修改变量时,其他线程在读取这个变量时可能会看到一个不一致的值,在变量修改时间多余一个存储器访问周期的处理器结构中,当存储器读与存储器写这两个周期交叉时,这种不一致就会出现。
比如两个线程试图在同一时间修改同一变量,也需要进行同步。考虑变量增量操作的情况,增量的操作通常分为3步:
【1】从内存单元读入到寄存器
【2】在寄存器中对变量做增量操作
【3】把新的值写回内存单元
如果两个线程试图几乎在同一时间对同一个变量做增量操作而不进行同步的话,结果就可能出现不一致,变量可能比原来增加了1,也有可能比原来增加了2。具体增加多少,要取决于第二个线程开始操作时获取的数值。

互斥量
互斥量从本质上说是一把锁,在访问共享资源前加锁,在访问完成后解锁,对互斥量进行加锁后,任何其他试图再次对互斥量加锁的线程都会被阻塞,直到当前线程释放该互斥锁。如果释放互斥量时有一个以上的线程被阻塞,那么所有该锁上的阻塞线程都会变成可运行的状态,第一个变为运行的线程就可以对互斥量加锁,其他线程就会看到互斥量依然是锁着的,只能回去再次等待它重新变为可用。
-
初始化与销毁
#include <pthread.h> int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr attr); int pthread_mutex_destroy(pthread_mutex_t *mutex); 2个函数返回值:成功返回0,否则返回错误编号可以用2种方式初始化:
- 静态变量的互斥锁使用
PTHREAD_MUTEX_INITIALIZER初始化 - 其他使用
pthread_cond_init函数对它进行初始化
- 静态变量的互斥锁使用
-
加锁
#include <pthread.h> int pthread_mutex_lock(pthread_mutex_t *mutex) int pthread_mutex_trylock(pthread_mutex_t *mutex) 2个函数返回值:成功返回0,否则返回错误编号如果互斥量已经上锁,调用线程将阻塞直到互斥量被解锁。如果调用线程不想被阻塞,那么可以用trylock加锁,互斥量被锁住时,trylock将失败返回EBUSY。
-
解锁
#include <pthread.h> int pthread_mutex_unlokc(pthread_mutex_t *mutex) -
代码示例:
多个线程对全局资源的访问#include <pthread.h> #define THREAD_NUM 20 // 线程数量 int num = 0; // 全局资源 pthread_mutex_t lock; void* thr_fn(void* arg) { pthread_mutex_lock(&lock); num++; printf("%lu: %d\n", pthread_self(), num); pthread_mutex_unlock(&lock); } int main() { int i = 0; pthread_t tid; pthread_mutex_init(&lock, NULL); for (; i != THREAD_NUM; i++) pthread_create(&tid, NULL, thr_fn, NULL); sleep(1); }
死锁
参考资料
[1]《UNIX环境高级编程》[美] W. Richard Stevens Stephen A. Rago