本文简单介绍互斥锁的使用
互斥锁变量类型
pthread_mutex_t
1.互斥锁初始化
1.1 动态初始化 需要销毁
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
参数说明:
mutex:传入互斥锁的地址
attr:属性,一般传递NULL采用默认属性
1.2 静态初始化 不需要销毁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
PTHREAD_MUTEX_INITIALIZER :宏定义了一个结构体的值
2.加锁
1.1 阻塞的加锁接口
int pthread_mutex_lock(pthread_mutex_t *mutex);
mutex:传入互斥锁的地址
如果mutex中计数器值为1,则pthread_mutex_lock接口直接返回,表示加锁成功,同时mutex中的计数器的值会被置为0
如果mutex中计数器值为0,则pthread_mutex_lock接口会阻塞在函数内部中,直到加锁成功
1.2 非阻塞加锁接口
int pthread_mutex_trylock(pthread_mutex_t *mutex);
mutex:传入互斥锁的地址
当mutex中的计数器值为1,则加锁成功直接返回
当mutex中的计数器值为0,也会返回,但是这时候没有加锁成功,所以不能访问临界资源
1.3 带有超时时间的加锁接口
int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex,
const struct timespec *restrict abs_timeout);
mutex:传入互斥锁的地址,abs_timeout : 等待的时间
1.带有超时时间的加锁接口,当没有获取互斥锁时,会等待abs_timeout时间,在这段时间中加锁成功了,就直接返回,如果等待超时,就直接返回,但是表示加锁失败了,需要循环使用进行加锁
注意:非阻塞接口一般都是配合循环使用
3.解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
mutex:传入互斥锁的地址
1.不管是使用哪个接口进行加锁的互斥锁都可以通过这个接口进行解锁
2.解锁的时候,会将互斥锁中的计时器的值置为1,表示其它线程可以获取这个互斥锁
4.互斥锁的销毁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
mutex:传入互斥锁的地址
针对动态初始化的互斥锁进行销毁
5.互斥锁的应用
这是一个黄牛抢票程序,4个工作线程代表4个黄牛,临界资源代表票,规则为:一张票只能被一个黄牛拿到。
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#define THREADCOUNT 4
// 票
int g_titcks = 100;
//定义一个互斥锁‘
pthread_mutex_t g_lock;
void* func(void* arg)
{
(void* ) arg;
while(1)
{
//加锁
pthread_mutex_lock(&g_lock);
if( g_titcks > 0)
{
printf("i am work thread %p , i have titck %d\n",pthread_self(), g_titcks);
g_titcks--;
}
else
{
//解锁
pthread_mutex_unlock(&g_lock);
break;
}
//解锁
pthread_mutex_unlock(&g_lock);
}
return NULL;
}
int main()
{
pthread_t tid[THREADCOUNT];
//互斥锁初始化
pthread_mutex_init(&g_lock,NULL);
for(int i = 0; i < THREADCOUNT; i++)
{
int ret = pthread_create(&tid[i], NULL, func, NULL);
if(ret < 0 )
{
perror("pthread_ create \n");
return -1;
}
}
for(int i = 0; i < THREADCOUNT; i++)
{
pthread_join(tid[i],NULL);
}
//互斥锁销毁
pthread_mutex_destroy(&g_lock);
return 0;
}