Linux编程-互斥锁

本文最后更新于:1 年前

  • 递归锁:在同一个线程可以多次获取同一个锁,不会产生死锁;
  • 非递归锁:在同一个线程中,加锁后不可以再次获取该锁,如果获取可能产生死锁;

Linux的互斥量pthread_mutex_t是非递归锁,但是可以在创建互斥量时设置PTHREAD_MUTEX_RECURSIVE属性,将pthread_mutex_t设置为递归锁。

1.创建互斥锁

pthread_mutex_t mtx; //定义互斥锁类型的变量

2.初始化互斥锁

//第二个参数为 NULL,互斥锁的属性会设置为默认属性

pthread_mutex_init(&mtx, NULL);

3.获取互斥锁

3.1* *阻塞调用

pthread_mutex_lock(&mtx);

如果这个锁此时正在被其它线程占用, 那么 pthread_mutex_lock() 调用会进入到这个锁的排队队列中,并会进入阻塞状态, 直到拿到锁之后才会返回。

3.2* *非阻塞调用

1
2
3
4
5
6
7
int err = pthread_mutex_trylock(&mtx);

if(0 != err) {
if(EBUSY == err) {
//The mutex could not be acquired because it was already locked.
}
}

如果不想阻塞,而是想尝试获取一下,如果锁被占用就不用,如果没被占用那就用, 可以使用 pthread_mutex_trylock() 函数。 当请求的锁正在被占用的时候, 不会进入阻塞状态,而是立刻返回,并返回一个错误代码 EBUSY

3.3* *超时调用

1
2
3
4
5
6
7
8
9
10
11
struct timespec abs_timeout;
abs_timeout.tv_sec = time(NULL) + 1;
abs_timeout.tv_nsec = 0;

int err = pthread_mutex_timedlock(&mtx, &abs_timeout);

if(0 != err) {
if(ETIMEDOUT == err) {
//The mutex could not be locked before the specified timeout expired.
}
}

如果不想不断的调用 pthread_mutex_trylock() 来测试互斥锁是否可用, 而是想阻塞调用,但是增加一个超时时间,那么可以使用 pthread_mutex_timedlock() 来解决。上面代码的意思是,阻塞等待线程锁,但是只等1秒钟,一秒钟后如果还没拿到锁的话, 那就返回,并返回一个错误代码 ETIMEDOUT,意思是超时了。

4.释放互斥锁

pthread_mutex_unlock(&mtx);

5.销毁互斥锁

pthread_mutex_destroy(&mtx)

通过 man pthread_mutex_destroy 命令可以看到 pthread_mutex_destroy() 函数的说明, 在使用此函数销毁一个线程锁后,线程锁的状态变为”未定义”。有的 pthread_mutex_destroy 实现方式,会使线程锁变为一个不可用的值。一个被销毁的线程锁可以被 pthread_mutex_init() 再次初始化。对被销毁的线程锁进行其它操作,其结果是未定义的。