多线程间协调资源之互斥锁

互斥锁:用于协调多线程访问同一共享资源的完整性;保证了同一时刻不存在多个线程同时访问一块共享资源的数据;

(1)当一个线程给这个资源上锁且还没有解锁前,其他线程是无法对该资源进行访问的
(2)当一个线程对一块共享资源进行访问时上了锁,但是其他资源此时也想进行访问,则会挂起直到当前访问资源的线程解锁后,才会被唤醒再去访问
(3)每次线程进行访问时上锁后,访问结束后一定记得解锁,否则会导致形成死锁,其他线程无法上锁,也无法访问

在这里插入图片描述

就如:现在有一个资源,但是呢这个资源是很多线程都可以去访问的,我们假设这块内存的资源是一栋房子;然后这个时候为了防止一下子每个人都涌进去出现一块内存同时被多个线程操作,出现数据混乱等问题,我们就在它门口装上一把锁,这把锁只有一条钥匙,当线程1抢到钥匙后就可以把门给上锁不让其他线程进来,这个时候其他线程没办法只能在门口睡觉直到线程1出来后把门解锁了再把钥匙丢出去让大家抢,当然线程1也是可以再去参与抢钥匙的,如果再次被线程1抢到,线程1就会再次进去;但是也存在线程1出来后把把门的锁解开钥匙就一直拿在手里,这样则会形成死锁,然后线程1每次访问都要上一次锁的,但是本来它就没有解锁,因此因为有一把琐了,它再想上锁是不行的,这样就导致了大家都不能进去形成死锁了



互斥锁常用函数:

//定义互斥锁时,系统宏定义了PTHREAD_MUTEX_INITIALIZER这个宏用于静态初始化互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//初始化互斥锁函数
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
           const pthread_mutexattr_t *restrict attr);


//函数介绍:
/********************************************************
函数作用:用于初始化一个互斥锁(restrict代表对象已经被指针所引用,不能通过除该指针外所有其他直接或间接的方式修改该对象的内容)

形参:mutex:我们定义的互斥锁

	 attr:初始化互斥锁给它的属性(一般可给NULL)

返回值:
		成功:0
		失败:错误码


********************************************************/ 

//给互斥锁上锁的函数
int pthread_mutex_lock(pthread_mutex_t *mutex);

//尝试给一个互斥锁上锁,上锁不成功不阻塞等待(不常用)
int pthread_mutex_trylock(pthread_mutex_t *mutex);

//给一个互斥锁解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);


//函数介绍:
/********************************************************
函数作用:
	pthread_mutex_lock:用于给一个互斥锁上锁,若已被其他线程上锁则阻塞等待
	pthread_mutex_trylock:尝试给一个互斥锁上锁;上锁成功返回0,失败直接返回
	pthread_mutex_unlock:给一个互斥锁解锁

形参:mutex:我们在前面定义的互斥锁

返回值:
		成功:0
		失败:相对应的错误码


********************************************************/ 

//销毁互斥锁函数
int pthread_mutex_destroy(pthread_mutex_t *mutex);
//函数介绍:
/********************************************************
函数作用:用于销毁一个互斥锁

形参:mutex:我们定义的互斥锁

返回值:
		成功:0
		失败:错误码


********************************************************/ 
      


测试代码:

单个互斥锁使用代码:
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>

char buf[128];

//定义互斥锁
pthread_mutex_t mutex;

void *func(void *arg)
{
	char*buf1=(char*)arg;
	for(int i=0;i<10;i++)
	{
		//上锁
		pthread_mutex_lock(&mutex);
		
		//打印一下传递的参数
		printf("i am %s\n",buf1);
		
		//解锁
		pthread_mutex_unlock(&mutex);
		
		//睡眠1微秒,防止重复抢到锁
		usleep(1);	
	}

}
void *func1(void *arg)
{
	char*buf1=(char*)arg;
	for(int i=0;i<10;i++)
	{
		//上锁
		pthread_mutex_lock(&mutex);
		
		//打印一下传递的参数
		printf("i am %s\n",buf1);
		
		//解锁
		pthread_mutex_unlock(&mutex);
		
		//睡眠1微秒,防止重复抢到锁
		usleep(1);	
	}

}

int main(int argc,char **argv)
{
	//初始化互斥锁
	pthread_mutex_init(&mutex,NULL);

	//创建两个线程
	pthread_t id1,id2;

	pthread_create(&id1,NULL,func,"zhangsan");
	pthread_create(&id2,NULL,func1,"lisi");

	//睡眠1秒防止互斥锁被提前销毁
	sleep(1);
	
	//销毁互斥锁
	pthread_mutex_destroy(&mutex);

	//回收线程资源
	pthread_join(id1,NULL);	
	pthread_join(id2,NULL);	

	return 0;
}

运行结果:

在这里插入图片描述

当线程创建后,由于线程2先抢到锁因此先打印了lisi,然后因为加了延时,因此间隔输出,否则会因为计算机的运行速度太快先执行完一个线程的再去执行另外一个线程的


多个互斥锁的用法:
/*
	测试互斥锁,在写入时不能读取,在读取时不能写入
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

//定义两个互斥锁,一个用于写入数据的锁,一个作于读取的锁
pthread_mutex_t mutex;//写入数据的锁
pthread_mutex_t mutex1;//读取的锁

void *func(void *arg)
{
	//把arg的类型强转为char *
	char *buf = (char *)arg;
	while(1)
	{
		//读取前上锁(可以读取数据)
		pthread_mutex_lock(&mutex1);
		
		//打印读取的结果
		printf("data:%s\n",buf);
			
		//读取结束后解锁(然后可以从键盘输入数据)
		pthread_mutex_unlock(&mutex);
	}

}


int main()
{
	//初始化互斥锁
	pthread_mutex_init(&mutex,NULL);
	pthread_mutex_init(&mutex1,NULL);

	//先给读取的上一个锁,防止先执行了
	//上锁
	pthread_mutex_lock(&mutex1);
	

	//定义一个数组,用于从键盘获取数据
	char data[20];
	bzero(data,20);

	//创建一个线程
	pthread_t id;

	//创建一个线程
	pthread_create(&id,NULL,func,data);

	//循环输入数据
	while(1)
	{
		//上锁(可以写入数据)
		pthread_mutex_lock(&mutex);

		//每次输入前清空一下数组
		bzero(data,20);
		
		printf("请输入要发送的数据:");
		fgets(data,20,stdin);
	
		//解锁(可以读取数据)
		pthread_mutex_unlock(&mutex1);
	}
	
	//销毁互斥锁
	pthread_mutex_destroy(&mutex);
	pthread_mutex_destroy(&mutex1);

	return 0;
}

运行结果:

执行结果

当线程创建后,由于先给读取的上了锁,因此不会出现还没开始输入就打印的情况,而是会每次等输入结束后给读取解锁才会去执行读取数据的线程的代码,否则会一直处于挂起状态等待解锁



总结:

(1)每次操作完记得解锁,否则其他线程则无法进行操作
(2)互斥锁只有两种情况:上锁,解锁
(3)互斥锁保证了多线程访问统一资源时,资源的完整性;即同一时间不允许多线程访问
(4)一个线程一个取得锁多次(如:测试代码1若不加延时会导致一个线程多次拿到锁)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
互斥锁是一种保护共享资源的机制,多个线程可以通过互斥锁来访问共享资源,避免多个线程同时访问共享资源导致的竞争问题。在使用互斥锁时,需要注意以下几点: 1. 初始化互斥锁:在使用互斥锁前,需要先进行初始化。可以使用 `pthread_mutex_init()` 函数来进行初始化。 2. 加和解:在访问共享资源前,需要先加使用 `pthread_mutex_lock()` 函数来加使用 `pthread_mutex_unlock()` 函数来解。加后,其他线程无法访问共享资源,直到当前线程解。 3. 避免死:由于互斥锁是一种独占资源的机制,如果多个线程同时请求多个互斥锁,很容易导致死。为了避免死,需要对多个互斥锁的加顺序进行协调,保证所有线程按照相同的顺序请求互斥锁。 下面是一个使用互斥锁的简单示例代码: ```c++ #include <pthread.h> #include <stdio.h> pthread_mutex_t mutex; void *thread_func(void *) { pthread_mutex_lock(&mutex); // 加 printf("Thread %ld is running\n", pthread_self()); pthread_mutex_unlock(&mutex); // 解 return NULL; } int main() { pthread_t threads[10]; pthread_mutex_init(&mutex, NULL); // 初始化互斥锁 for (int i = 0; i < 10; i++) { pthread_create(&threads[i], NULL, thread_func, NULL); } for (int i = 0; i < 10; i++) { pthread_join(threads[i], NULL); } pthread_mutex_destroy(&mutex); // 销毁互斥锁 return 0; } ``` 在上面的代码中,我们创建了 10 个线程,每个线程都会尝试获取互斥锁,打印自己的线程 ID,然后释放互斥锁。由于互斥锁的存在,每次只有一个线程能够获取到互斥锁,其他线程需要等待前一个线程释放互斥锁后才能获取到互斥锁

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值