信号量PV操作mutex互斥锁

本文介绍了线程间的通信方式,通过全局变量实现线程间数据传递,并讨论了线程执行顺序的不确定性。为了解决这一问题,引入了同步机制的PV操作,通过信号量控制生产者与消费者问题,以及读写问题。同时,互斥机制中的互斥锁也在访问临界资源时确保数据正确性。文章以实例展示了如何在C语言中实现这些概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程是共享相同地址空间的多个任务。所以线程之间通信可以利用 静态数据(全局变量)作为中介来实现。前面关于线程的创建中有给出例子。但是线程与主线程之间的执行顺序这个无法确定,主要看在时间片中能执行多少指令,也可以使用sleep()函数来延缓下面的指令的执行。

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>

char a[64]="I love you!";

void *fuc()
{
	sleep(1);
	stpcpy(a,"I hate you !");
	pthread_exit("come from pthread_exit");

}

int main()
{
	pthread_t a_thread;
	void *result;
	
	if((pthread_create(&a_thread,NULL,&fuc,NULL))!=0)
	{
		printf("pthread_creat is failed!\n");
		exit(-1);
	}
	printf("%s\n",a);  //此时a里面数据还未被线程修改,因为fuc里面有sleep
	
	sleep(3);

	printf("%s\n",a); //此时a里面的数据已经被修改,因为主线程sleep 3 a线程已经执行完
	
	stpcpy(a,"I love you,too!");
	printf("%s\n",a);
	
	pthread_join(a_thread,&result);
	printf("%s\n",(char*)result);
	
	return 0;
}

最后的结果如图:

 

 由于线程之间的执行顺序不确定性较大,为了消除不确定性导致的问题,引入了同步机制和互斥机制。

同步机制,是指多个任务按照约定的先后顺序相互配合完成一件事。为了执行同步机制还引入了信号量的P,V操作,P申请资源,V释放资源。

比如经典的生产者与消费者问题,读写问题,必须要在buf中写入数据之后才能进行读,在读的过程中不能进行写操作。

#include<stdio.h>
#include<semaphore.h>
#include<unistd.h>
#include<pthread.h>
#include<string.h>
#include<stdlib.h>

char buf[32];
sem_t sem_r;  //可读缓冲区的个数
sem_t sem_w;  //可写缓冲区的个数

void *function(void *arg);

int main()
{
	pthread_t a_thread;
	
	if(sem_init(&sem_r,0,0)<0){    //初始化信号量,刚开始可读的资源为0
		perror("sem_init");     
		exit(-1);
	}
	
	if(sem_init(&sem_w,0,1)<0){    //初始化信号量,刚开始可写的资源为1
		perror("sem_init");     
		exit(-1);
	}
	
	if(pthread_create(&a_thread,NULL,&function,NULL)!=0) //需要先初始化信号量再创线程,因为                                                                                                                                                        
	{                                   //如果先创线程再初始化可能导致初始化两遍信号量
		printf("pthread_create is failed!\n");
		exit(-1);
	}
	
	printf("input 'quit' to exit\n");
	
	do{
		sem_wait(&sem_w);             //写之前先申请写资源 P(w)
		fgets(buf,32,stdin); 
		sem_post(&sem_r);              //写之后释放资源增加可读资源 v(r)
	}while(strncmp(buf,"quit",4)!=0);
	return 0;
}

void *function(void *arg)
{
	while(1)
	{
		sem_wait(&sem_r);          //读之前申请读的资源 p(r)
		printf("you enter %ld characters\n",strlen(buf));
		sem_post(&sem_w);           //读之后释放资源 增加可写的资源 v(w)
	}
}

互斥机制,使用mutex互斥锁,在访问临界资源时申请锁,访问完解锁。

当pv操作中的信号量只有01时也相当于互斥锁。

总结:

线程由于共享相同地址空间,所以通信很方便,但也容易由执行顺序导致通信出错。

引入pv操作和互斥锁来确保数据的正确性。

### PV操作互斥锁的关系 PV操作是一种用于进程间通信和同步的机制,通过信号量(Semaphore)来控制资源访问。P操作通常表示“wait”,即等待某个条件满足;V操作则表示“signal”,即通知其他进程某条件已满足[^1]。 在操作系统中,互斥锁Mutex Lock)的作用是确保同一时刻只有一个线程能够进入临界区,从而保护共享资源的安全访问。PV操作可以通过信号量实现类似的互斥功能[^2]。 --- ### 使用PV操作实现互斥锁的原理 为了实现互斥锁的功能,可以定义一个初始值为1的二元信号量S。当多个进程试图访问同一个共享资源时: - P(S):如果信号量S大于0,则将其减1并继续执行;否则阻塞当前进程直到另一个进程释放该资源。 - V(S):将信号量S加1,并唤醒因竞争此资源而被挂起的一个进程。 这种设计保证了任何时间点最多只有一个进程能持有这个虚拟“钥匙”——也就是进入了它的临界区域。 --- ### 示例代码及其解释 以下是利用Python模拟基于PV操作互斥锁的例子: ```python import threading class Semaphore: def __init__(self, value=1): self._value = value self._lock = threading.Lock() self._condition = threading.Condition(self._lock) def p(self): # 等待操作 (Proberen/Wait) with self._condition: while self._value <= 0: self._condition.wait() # 如果信号量小于等于零,则等待 self._value -= 1 # 否则减少计数器 def v(self): # 唤醒操作 (Verhogen/Signal) with self._condition: self._value += 1 # 增加计数器 self._condition.notify() # 唤醒一个正在等待的线程 def critical_section(lock, thread_name): lock.p() # 尝试获取锁 print(f"{thread_name} entered the critical section.") # 模拟一些工作... import time; time.sleep(1) print(f"{thread_name} leaving the critical section.") lock.v() # 释放锁 if __name__ == "__main__": semaphore_lock = Semaphore() threads = [] for i in range(5): t = threading.Thread(target=critical_section, args=(semaphore_lock, f"Thread-{i+1}",)) threads.append(t) for t in threads: t.start() for t in threads: t.join() ``` #### 代码说明: 1. **`Semaphore` 类** 实现了一个简单的信号量结构体,其中包含了 `p()` 和 `v()` 方法分别代表P/V操作。 2. 在函数 `critical_section` 中展示了如何使用这些方法来管理对共享资源的独占访问。 3. 创建五个独立运行的工作线程去尝试进入它们各自的临界部分,但由于采用了上述提到的技术手段,每次只会有一个成功获得许可权。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值