异想天开

What's the true meaning of light, Could you tell me why

线程同步

日期:2015-04-10 23:35:55
  
最后更新日期:2015-07-20 09:56:54
【技术】
1.互质锁
多个线程竞争某个共享变量,最常见会用到互斥锁来保护。同时可以简单封装为C++的类的形式,利用局部对象的作用域,析构时自动释放互斥锁。 [code lang="cpp"]
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
[/code]
注意点:
互斥锁分为几种类型:
PTHREAD_MUTEX_NORMAL 若某个线程unlock一个没有lock的锁变量是未定义的行为,而lock一个lock状态的锁变量,会发生死锁
PTHREAD_MUTEX_ERRORCHECK 若某个线程unlock一个没有lock的锁变量或lock一个lock状态的锁变量都会报错
PTHREAD_MUTEX_RECURSIVE 若某个线程,可以递归的lock该锁变量

2.读写锁
读写锁,对互斥锁的改进,将请求分为两种读请求和写请求。使用读写锁时,可以拥有多个读锁,任何时刻最多只有一个写锁。通常, 当读写锁处于读模式锁住状态时, 如果有另外线程试图以写模式加锁, 读写锁通常会阻塞随后的读模式锁请求, 这样可以避免读模式锁长期占用, 而等待的写模式锁请求长期阻塞。
[code lang="cpp"]
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
[/code]

3.条件变量
前面两种锁,我的理解就是类似自旋锁一样,使用时锁的时间不会太长,只是避免线程竞争。而条件变量,则指定了等待什么条件,这种可以实现类似信箱的机制,等待邮递员投递进来信,邮递员唤醒主人翁取信。条件变量一般会与互斥量结合使用。
[code lang="cpp"]
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
[/code]
注意:
pthread_cond_broadcast是广播消息,会唤醒所有等待该条件变量的线程,故线程在被唤醒后,还需要检查条件是否满足。一个使用的场景是:
[code lang="cpp"]
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
mail=0;
//生产者
pthread_mutex_lock(&mutex);
mail++;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
//消费者
pthread_mutex_lock(&mutex);
//防止意外唤醒,比如错误使用了pthread_cond_broadcast
while(mail<=0){
pthread_cond_wait(&cond,&mutex);
}
while(mail>0){
mail--;
}
pthread_mutex_unlock(&mutex);
[/code]
注意:
1.若唤醒是没有线程在等待条件时,man手册上说明了:
[code lang="cpp"]
The pthread_cond_broadcast() and pthread_cond_signal() functions shall
have no effect if there are no threads currently blocked on cond
[/code]
注意消费者使用了一个循环来处理消息,因为之前可能消息积压了。

4.信号量
信号量也可以在线程同步时使用。这种记得操作系统课程设计时用过,后面再也没有用过。感觉有一些弊端,比如接口复杂,假设进程crash了,锁还在怎么办。故这里省略其api。