锁是一个常见的同步概念,我们都听说过加锁(lock)或者解锁(unlock),当然学术一点地说法是获取(acquire)和释放(release)。
恰好pthread包含这几种锁的API,而C++11只包含其中的部分。接下来我将通过pthread的API来展开回答。
mutex(互斥量)
mutex(mutual exclusive)即互斥量(互斥体)。也便是常说的互斥锁。
尽管名称不含lock,但是称之为锁,也是没有太大问题的。mutex无疑是最常见的多线程同步方式。其思想简单粗暴,多线程共享一个互斥量,然后线程之间去竞争。得到锁的线程可以进入临界区执行代码。
// 声明一个互斥量
pthread_mutex_t mtx;
// 初始化
pthread_mutex_init(&mtx, NULL);
// 加锁
pthread_mutex_lock(&mtx);
// 解锁
pthread_mutex_unlock(&mtx);
// 销毁
pthread_mutex_destroy(&mtx);
mutex是睡眠等待(sleep waiting)类型的锁,当线程抢互斥锁失败的时候,线程会陷入休眠。优点就是节省CPU资源,缺点就是休眠唤醒会消耗一点时间。另外自从Linux 2.6版以后,mutex完全用futex的API实现了,内部系统调用的开销大大减小。
值得一提的是,pthread的锁一般都有一个trylock的函数,比如对于互斥量:
ret = pthread_mutex_trylock(&mtx);
if (0 == ret) { // 加锁成功
...
pthread_mutex_unlock(&mtx);
} else if(EBUSY == ret){ // 锁正在被使用;
...
}
pthread_mutex_trylock用于以非阻塞的模式来请求互斥量。就好比各种IO函数都有一个noblock的模式一样,对于加锁这件事也有类似的非阻塞模式。
当线程尝试加锁时,如果锁已经被其他线程锁定,该线程就会阻塞住,直到能成功acquire。但有时候我们不希望这样。pthread_mutex_trylock在被其他线程锁定时,会返回特殊错误码。加锁成返回0,仅当成功但时候,我们才能解锁在后面进行解锁操作!
C++11开始引入了多线程库<thread>,其中也包含了互斥锁的API:std::mutex 。
此外,依据同一线程是否能多次加锁,把互斥量又分为如下两类:
- 是&#x