进程同步

Posted 丁帅帅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了进程同步相关的知识,希望对你有一定的参考价值。

1、实现两或多个进程之间互斥访问临界资源(先写出PV操作的伪算法,然后进行算法实现)

PV操作

semaphore mutex=1; //临界区互斥信号量

while(1){

     sleep(1);
     P(mutex);				
     printf("father in\\n");
     sleep(1);
     printf("father out\\n");
     V(mutex);
    
}

while(1){

    sleep(1);
    P(mutex);	
    printf("child in\\n");
    sleep(1);
    printf("child out\\n");
    V(mutex);
    
}

代码实现

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<linux/sem.h> 
#include <sys/wait.h>
int mutex;

int P(int sem_id)
{
    struct sembuf p;
    p.sem_num = 0;
	p.sem_op = -1;
	p.sem_flg = SEM_UNDO;
	if (semop(sem_id,&p,1) == -1)
	{
		fprintf(stderr, "P failed\\n");
		return 0;
	}

	return 1;
}


int V(int sem_id)
{
    struct sembuf v;
    v.sem_num = 0;
	v.sem_op = 1;
	v.sem_flg = SEM_UNDO;
	if (semop(sem_id,&v,1) == -1)
	{
		fprintf(stderr, "V failed\\n");
		return 0;
	}

	return 1;
}
int main()
{
	int child, i, j;
	// 定义信号量,初值为1
	mutex = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
	if (semctl(mutex, 0, SETVAL, 1) == -1)
	{
		perror("semctl setval error");
	}

	
	child = fork();
	while (1)
	{
		if (child == -1)
		{
			printf("error");
		}
		// 父进程
		else if (child > 0)
		{
			i = 1;
			while (i <= 3)
			{
				sleep(1);
				P(mutex);				
				printf("father in\\n");
				sleep(1);
				printf("father out\\n");
				V(mutex);
				i++;
			}
			wait(NULL);
			semctl(mutex, IPC_RMID, 0);
			exit(0);
		}
		// 子进程
		else if (child == 0)
		{
			j = 1;
			while (j <= 3)
			{
				sleep(1);
				P(mutex);	
				printf("child in\\n");
				sleep(1);
				printf("child out\\n");
				V(mutex);
				j++; 
			}
		}
	}
	return 0;
}


截图

2、实现不死锁的哲学家进餐问题(先写出PV操作的伪算法,然后进行算法实现)

PV操作

semaphore chopstick[5]={1,1,1,1,1}; 
semaphore mutex = 4; //互斥地取筷子,至多四个人同时拿左边的筷子,保证至少有一个人可以进餐,最终释放筷子使更多的人进餐 

Pi (){ //i号哲学家的进程
	 while(1){ 
	  思考… 
	  P(mutex); 
	  P(chopstick[i]); //拿左 
	  P(chopstick[(i+1)%5]); //拿右 
	  吃饭… 
	  V(chopstick[i]); //放左
	  V(chopstick[(i+1)%5]); //放右
	  V(mutex); 
 	  
   } 
 }

代码实现

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<signal.h>
#include<errno.h>
#include<fcntl.h>
int mutex = 4;//互斥地取筷子 
int chopstick[5];
int P(int sem_id)
{
	struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = -1;
	sem_b.sem_flg = SEM_UNDO;

	// 进行p操作
	if (semop(sem_id, &sem_b, 1) == -1)
	{
		fprintf(stderr, "P failed\\n");
		return 0;
	}
	return 1;
}
int V(int sem_id) // 释放资源
{
	struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = 1;
	sem_b.sem_flg = SEM_UNDO;

	// 进行v操作
	if (semop(sem_id, &sem_b, 1) == -1)
	{
		fprintf(stderr, "V failed\\n");
		return 0;
	}
	return 1;
}
int main()
{
	mutex = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
	semctl(mutex, 0, SETVAL, 4); // 至多只允许四个哲学家同时进餐,至少有一个可以拿到筷子
	int i = 0;
	pid_t pid;
    pid_t pids[3];
    char ch;
	for (i = 0; i < 5; ++i)
	{
		chopstick[i] = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
		semctl(chopstick[i], 0, SETVAL, 1);
	}
	for (i = 0; i < 5; ++i)
	{
		pid = fork();
		if (pid == 0)
		{
			while (1)
			{
				
				printf(" %d 哲学家在思考\\n",i);
				sleep(1);				
				P(mutex); 
				printf("%d 哲学家饿了,准备开始吃饭\\n",i);	
				P(chopstick[i]);
				printf("%d 哲学家拿左筷子\\n", i);	
				P(chopstick[(i + 1) % 5]);
				printf("%d哲学家拿右筷子\\n", i);		
				printf("%d 哲学家有两只筷子后,开始进餐!\\n", i);	
				V(chopstick[(i + 1) % 5]);
				printf(" %d 吃完饭了,释放右筷子\\n", i);	
				V(chopstick[i]);
				printf("%d 哲学家吃完饭了,释放左筷子\\n", i);				
				V(mutex);
			}
		}
	}
	 do{
      	ch = getchar();
      	if (ch == \'q\')
      	{
      		for (i = 0; i < 3; ++i)
	        {
	        	kill(pids[i],SIGTERM);
	        }
      	}
      }while(ch != \'q\');
	return 0;

}


截图

3、苹果-橘子问题,一个盘子可以放3个水果,爸爸放,儿子和女儿吃,假设儿子和女儿有永远吃不饱。(先写出PV操作的伪算法,然后进行算法实现)

PV操作

semaphore empty =3; // 盘子中最多容纳3个水果
semaphore full = 0; // 盘子现在不满,且0个水果
semaphore orange=0;//盘子中橘子的数量
semaphore apple=0;//盘子中苹果的数量


dad(){
	while(1){
	    if (rand() % 2 == 1)//随机放
		{
            准备一个苹果;
            p(empty);//申请一个盘子
            V(apple);//唤醒女儿吃苹果
		}
		else
		{
            准备一个橘子;
            P(empty);//申请一个盘子
            向盘子放橘子;
            V(orange);//唤醒儿子吃苹果
		}
	}
}

daughter(){
	while(1){
		P(orange);//申请橘子,若orange=0,则等待放入水果
		从盘子拿橘子;
		V(empty);///释放一个盘子
		吃橘子;
	}
}
son(){
	while(){
		P(apple);//申请苹果,若apple=0,则等待父亲放入水果
		从盘子中拿苹果;
		V(empty);//释放一个盘子
	}
}

代码

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<signal.h>
#include<errno.h>
#include<fcntl.h>

int P(int sem_id)
{
	struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = -1;
	sem_b.sem_flg = SEM_UNDO;

	// 进行p操作
	if (semop(sem_id, &sem_b, 1) == -1)
	{
		fprintf(stderr, "P failed\\n");
		return 0;
	}
	return 1;
}
int V(int sem_id) // 释放资源
{
	struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = 1;
	sem_b.sem_flg = SEM_UNDO;

	// 进行v操作
	if (semop(sem_id, &sem_b, 1) == -1)
	{
		fprintf(stderr, "V failed\\n");
		return 0;
	}
	return 1;
}
int main()
{
	int i = 0;
	pid_t pid;
    pid_t pids[3];
    char ch;
	int empty; // 盘子中是否为空
	int full; // 盘子中是否为满
	int apple; // 苹果有几个
	int orange; // 橘子有几个
   
	empty = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
	if (semctl(empty, 0, SETVAL, 3) == -1) // 盘子中最多容纳3个水果
	{
		perror("semctl setval error");
	}

	full = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
	if (semctl(full, 0, SETVAL, 0) == -1) // 盘子现在不满,且0个水果
	{
		perror("semctl setval error");
	}

	apple = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
	if (semctl(apple, 0, SETVAL, 0) == -1)
	{
		perror("semctl setval error");
	}

	orange = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
	if (semctl(orange, 0, SETVAL, 0) == -1)
	{
		perror("semctl setval error");
	}

	for (i = 0; i < 3; ++i)
	{
		pid = fork();
		if (pid == 0)
		{
			while (1)
			{
				if (pid == 0 && i == 0)
				{
					P(empty);
					if (rand() % 2 == 1)//随机放
					{
						printf("爸爸向盘子中放苹果\\n");
						V(apple);
						V(full);
					}
					else
					{
						printf("爸爸向盘子中放橘子\\n");
						V(orange);
						V(full);
					}
					sleep(2);
				}
				else if (pid == 0 && i == 1)
				{
					P(full);
					P(apple);
					printf("儿子从盘子中取走苹果\\n");
					V(empty);
					sleep(2);
				}
				else if (pid == 0 && i == 2)
				{
					P(full);
					P(orange);
					printf("女儿从盘子中取走橘子\\n", empty);
					V(empty);
					sleep(2);
				}
			}
		}
	}
      
      do{
      	ch = getchar();
      	if (ch == \'q\')
      	{
      		for (i = 0; i < 3; ++i)
	        {
	        	kill(pids[i],SIGTERM);
	        }
      	}
      }while(ch != \'q\');
	return 0;
}

截图

有的要别人来设定目标,有的给别人设定目标; 有的需要感情支持生活,有的需要意志支持生活。

以上是关于进程同步的主要内容,如果未能解决你的问题,请参考以下文章

进程线程同步异步

互斥与同步

OS学习笔记四:同步机制

进程互斥与同步

在 Python 多处理进程中运行较慢的 OpenCV 代码片段

[工作积累] UE4 并行渲染的同步 - Sync between FParallelCommandListSet & FRHICommandListImmediate calls(代码片段