Linux 互斥锁

1.进程线程间的互斥相关背景概念

  • 临界资源:多线程执行流共享的资源就叫做临界资源
  • 临界区:每个线程内部,访问临界资源的代码,就叫做临界区
  • 互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用
  • 原子性(后面讨论如何实现):不会被任何调度机制打断的操作,该操作只有两态要么完成,要么未完成

2.引入

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
int ticket = 100;
void* route(void* arg)
{
	char* id = (char*)arg;
	while (1) {
		if (ticket > 0) {
			usleep(1000);
			printf("%s sells ticket:%d\n", id, ticket);
			ticket--;
		}
		else {
			break;
		}
	}
}
int main(void)
{
	pthread_t t1, t2, t3, t4;
	pthread_create(&t1, NULL, route, "thread 1");
	pthread_create(&t2, NULL, route, "thread 2");
	pthread_create(&t3, NULL, route, "thread 3");
	pthread_create(&t4, NULL, route, "thread 4");
	pthread_join(t1, NULL);
	pthread_join(t2, NULL);
	pthread_join(t3, NULL);
	pthread_join(t4, NULL);
}

为什么可能无法获得争取结果?

  • if 语句判断条件为真以后,代码可以并发的切换到其他线程
  • usleep 这个模拟漫长业务的过程,在这个漫长的业务过程中,可能有很多个线程会进入该代码段
  • --ticket 操作本身就不是一个原子操作 

要避免ticket为负数,我们需要对ticket进行保护,也就是加上互斥锁,让各个线程在同一时间只能有一个对ticket进行访问。

3.互斥量的接口

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER//全局锁初始化,会自动销毁

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict
attr);//局部锁初始化
//参数:
//mutex:要初始化的互斥量
//attr:一般为NULL即可

int pthread_mutex_destroy(pthread_mutex_t *mutex);//局部锁销毁

int pthread_mutex_lock(pthread_mutex_t *mutex);//加锁

int pthread_mutex_unlock(pthread_mutex_t *mutex);//解锁

下面我们来改进上面的代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
int ticket = 100;
pthread_mutex_t mutex;
void* route(void* arg)
{
	char* id = (char*)arg;
	while (1) {
		pthread_mutex_lock(&mutex);//2.加锁
		if (ticket > 0) {
			usleep(1000);
			printf("%s sells ticket:%d\n", id, ticket);
			ticket--;
			pthread_mutex_unlock(&mutex);//3.解锁
			
		}
		else {
			pthread_mutex_unlock(&mutex);
			break;
		}
	}
}
int main(void)
{
	pthread_t t1, t2, t3, t4;
	pthread_mutex_init(&mutex, NULL);//1.初始化
	pthread_create(&t1, NULL, route, "thread 1");
	pthread_create(&t2, NULL, route, "thread 2");
	pthread_create(&t3, NULL, route, "thread 3");
	pthread_create(&t4, NULL, route, "thread 4");
	pthread_join(t1, NULL);
	pthread_join(t2, NULL);
	pthread_join(t3, NULL);
	pthread_join(t4, NULL);
	pthread_mutex_destroy(&mutex);//4.销毁锁
}

 这样我们通过互斥锁对临界资源ticket进行保护,确保了同一时间只有一个进程对ticket进行访问,保证票数正常。

4.互斥锁的实现

伪代码如下:

al代表cpu的一个寄存器,lock操作先是把寄存器al置为0,然后再交换互斥量和al的值 ,这里都是一句汇编完成。这样mutex初始为1,在之后的任一时刻,在al寄存器和mutex中,只会有一个为1,当al为1,就代表抢到了锁。同时al寄存器的内容属于硬件上下文,为线程私有,当线程切换时,线程会对自己的硬件上下文进行保存,这就保证在任何线程的al寄存器和mutex的值中只会有一个1。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值