操作系统经典问题

生产者消费者模型

生产者和消费者问题是计算机同步互斥的经典问题,其意思就是生产者把生产出来的产品放在仓库里,消费者把产品从仓库里取出来。仓库属于临界区,生产者和消费者一次只能一个进入临界区中。两个进程之间就有一个同步互斥问题,下面我将对该问题进行详细介绍。

什么是PV操作
  PV操作是由P操作原语和V操作原语组成(原语是不可能中断的过程),操作对象是信号量。具体的:
  P(S):① 将信号量S的值减1,即S=S-1;② 如果S>=0,则该进程继续执行;否则进程进入等待队列,置为等待状态。
  V(S):① 将信号量S的值加1,即S=S+1;② 如果S>0,则该进程继续执行;否则释放等待队列中第一个等待信号量的进程。(因为将信号量加1后仍然不大于0,则表示等待队列中有阻塞的进程。)

#define N 100     //缓冲区大小
typedef int semaphore;  //信号量是一种特殊的整形数据
semaphore mutex=1;   //控制对临界区的访问
semaphore empty=N;   //表示缓冲中空槽的数目
semaphore full=0;    //表示缓冲中满槽的数目

void produce()
{
    int item;
    while(true)
    {
        item=produce_item();  //产生一个数据
        P(&empty);  //将空槽的数目减一
        P(&mutex);  //进入临界区
        insert_item(item);  //将产生的数据插入临界区
        V(&mutex);  //离开临界区
        V(&full);   //将满槽的数目加1
    }
}

void consumer()
{
    int item;
    while(true)
    {
        P(&full);    //将满槽的数目减一
        P(&mutex);   //进入临界区
        item=remove_item();  //从缓冲区中取出一个数据
        V(&mutex);   //离开临界区
        V(&empty);   //将空槽数目加一

        consumer_item(item);  //处理数据
    }
}
        

哲学家就餐问题

转载于:哲学家就餐问题
有五个哲学家,他们的生活方式是交替地进行思考和进餐。他们共用一张圆桌,分别坐在五张椅子上。

在圆桌上有五个碗和五支筷子,平时一个哲学家进行思考,饥饿时便试图取用其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐。进餐完毕,放下筷子又继续思考。
在这里插入图片描述
哲学家进餐问题可看作是并发进程并发执行时处理共享资源的一个有代表性的问题

semphore chopstick[5]={1,1,1,1,1}
void philosopher(int i)   //哲学家编号,从0-4
{
	while (true)
	{
		think();   //哲学家在思考
		wait(chopstick[i]);    //拿起左边筷子
		wait(chopstick[(i + 1) % 5]);  //拿起右边筷子
		eat();   //吃饭
		signal(chopstick[i]);  //放下左边筷子
		signal(chopstick[(i + 1) % 5]);  //放下右边筷子
	}
}

此算法可以保证不会有相邻的两位哲学家同时进餐。

若五位哲学家同时饥饿而各自拿起了左边的筷子,这使五个信号量 chopstick 均为 0,当他们试图去拿起右边的筷子时,都将因无筷子而无限期地等待下去,即可能会引起死锁。

哲学家进餐问题的改进解法

  • 方法一:至多只允许四位哲学家同时去拿左筷子,最终能保证至少有一位哲学家能进餐,并在用完后释放两只筷子供他人使用。
  • 方法二:仅当哲学家的左右手筷子都拿起时才允许进餐。
  • 方法三:规定奇数号哲学家先拿左筷子再拿右筷子,而偶数号哲学家相反。

方法一
至多只允许四位哲学家同时去拿左筷子,最终能保证至少有一位哲学家能进餐,并在用完后释放两只筷子供他人使用。

设置一个初值为 4 的信号量 r,只允许 4 个哲学家同时去拿左筷子,这样就能保证至少有一个哲学家可以就餐,不会出现饿死和死锁的现象。

原理:至多只允许四个哲学家同时进餐,以保证至少有一个哲学家能够进餐,最终总会释放出他所使用过的两支筷子,从而可使更多的哲学家进餐。

semphore chopstick[5] = { 1,1,1,1,1 }
semphore r = 4;
void philosopher(int i)   //哲学家编号,从0-4
{
	while (true)
	{
		think();   //哲学家在思考
		wait(r);   //请求进餐
		wait(chopstick[i]);    //拿起左边筷子
		wait(chopstick[(i + 1) % 5]);  //拿起右边筷子
		eat();   //吃饭
		signal(chopstick[i]);  //放下左边筷子
		signal(chopstick[(i + 1) % 5]);  //放下右边筷子
		signal(r);  //释放信号量r
	}
}

方法二
仅当哲学家的左右手筷子都拿起时才允许进餐。

解法 1:利用 AND 型信号量机制实现。

原理:多个临界资源,要么全部分配,要么一个都不分配,因此不会出现死锁的情形。

semphore chopstick[5]={1,1,1,1,1}
void philosopher(int i)   //哲学家编号,从0-4
{
	while (true)
	{
		think();   //哲学家在思考
		Swait(chopstick[i]; chopstick[(i + 1) % 5]);    //同时拿起左边筷子和右边筷子
		eat();   //吃饭
		Ssignal(chopstick[i]; chopstick[(i + 1) % 5]);  //同时放下左边筷子和右边筷子
		think();
	}
}

解法 2:利用信号量的保护机制实现。

原理:通过互斥信号量 mutex 对 eat() 之前取左侧和右侧筷子的操作进行保护,可以防止死锁的出现。

semphore chopstick[5]={1,1,1,1,1}
semphore mutex = 1;
void philosopher(int i)   //哲学家编号,从0-4
{
	while (true)
	{
		think();   //哲学家在思考
		wait(&mutex);
		wait(chopstick[i]);    //拿起左边筷子
		wait(chopstick[(i + 1) % 5]);  //拿起右边筷子
		signal(&mutex);
		eat();   //吃饭
		signal(chopstick[i]);  //放下左边筷子
		signal(chopstick[(i + 1) % 5]);  //放下右边筷子
	}
}

方法三
规定奇数号哲学家先拿左筷子再拿右筷子,而偶数号哲学家相反。

原理:按照下图,将是 2,3 号哲学家竞争 3 号筷子,4,5 号哲学家竞争 5 号筷子。1 号哲学家不需要竞争。最后总会有一个哲学家能获得两支筷子而进餐。

semphore chopstick[5] = { 1,1,1,1,1 }
void philosopher(int i)   //哲学家编号,从0-4
{
	while (true)
	{
		think();   //哲学家在思考
		if (i % 2 == 0)  //偶数哲学家,先右后左
		{
			wait(chopstick[(i + 1) % 5]);  //拿起右边筷子
			wait(chopstick[i]);    //拿起左边筷子
			eat();   //吃饭
			signal(chopstick[(i + 1) % 5]);  //放下右边筷子
			signal(chopstick[i]);  //放下左边筷子
		}
		else   //奇数哲学家,先左后右
		{
			wait(chopstick[i]);    //拿起左边筷子
			wait(chopstick[(i + 1) % 5]);  //拿起右边筷子
			eat();   //吃饭
			signal(chopstick[i]);  //放下左边筷子
			signal(chopstick[(i + 1) % 5]);  //放下右边筷子
		}
	}
}

读者写者问题

参考:读者写者问题
1.问题描述
在这里插入图片描述
2.需要满足的条件

  • 写进程与写进程之间必须互斥的写入数据(因为如果两个写进程同时对共享数据中的区域A中的数据进行写操作的话,会导致数据错误覆盖的问题)
  • 写进程与读进程之间必须互斥的访问共享数据(因为写进程与读进程如果同时访问共享数据,可能会导致数据不一致的问题。比如:读进程A想要访问共享数据中的B数据,但是写进程C在读进程A访问B数据之前将B数据进行了更新,这就会导致读进程A读不到它想要读到的数据,从而出现数据不一致问题)
  • 读进程与读进程之间可以同时访问数据,不需要实现互斥的访问共享数据(因为读进程读数据,并不会像之前的生产者消费者问题中的消费者那样改变数据或者是将数据清空,所以多个读进程可以同时访问共享数据)

3.代码

typedef int semphore
semphore mutex = 1;   //控制对临界区的访问
semphore db = 1;   //控制对数据库的访问
int rc = 0;  //正在读或者即将读的进程数目

void reader()
{
	while (true)
	{
		P(&mutex);   //进入临界区
		rc = rc + 1;
		if (rc == 1)   //如果是第一个读者,将控制访问数据库的权限
		{
			P(&db);   //不让写者访问数据库
		}
		V(&mutex);  //退出临界区

		read_data_process();  //读取数据

		P(&mutex);    //进入临界区
		rc = rc - 1;   //将读者数减一
		if (rc == 0)   //如果是最后一个读者,表示写者可以访问数据库了
		{
			V(&db);   //释放数据库的访问权限
		}
		V(&mutex);   //退出临界区
	}
}

void writer()
{
	while (true)
	{
		P(&db);  //获取互斥访问数据库
		write_data_process();  //写数据
		V(&db);   //释放互斥访问
	}
}

死锁问题

可能发生死锁的情况

typedef int semphore
semphore resource_1 = 1;
semphore resource_2 = 1;

void process_1()
{
	P(&resource_1);
	P(&resource_2);

	process_A();

	P(&resource_2);
	P(&resource_1);
}

void process_2()
{
	P(&resource_2);
	P(&resource_1);

	process_B();

	P(&resource_1);
	P(&resource_2);
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
设计内容: 进程死锁的检测:资源分配图的化简判断是否有死锁发生 设计要求: •建立所需的数据结构。 •从文件中读取资源分配的情况(文件格式自定义)。 •编写资源分配图的化简算法。 •每化简一步,在屏幕上显示化简的当前结果。 •最后给出结论,是否死锁。如果死锁,给出死锁进程和资源。 设计思路: 程序中主要涉及两个方面:进程、资源。两者通过占有和申请发生联系。因此对于每一个进程Pi,建立“占有”和“申请”的数据结构来保存与之相关联的资源(由于事先不知道进程拥有和申请的资源数,故用Vector作为数据结构)。同时记录下程序处理的总的进程数目和资源数目。对于资源,另建立两个数组res和work分别记录第i类资源的总数和当前可用数。 从文件中读入资源和进程的情况时,要进行一些判断。①处理的资源和进程数目不得超过500(500已满足当前实际机器的情况)。②资源及进程的编号不得超过相应的数目也不得小于0。③资源的起始值不应该小于0。 ④起始情况下,所有进程拥有的第i资源总数不应该比其总的资源数目还要多。 由于在理论上已经证明,化简的次序不影响化简的最终结果。所以化简的过程就是不停的寻找满足条件(此进程所申请的资源全部都可以满足)的进程进行化简(即把它拥有的资源加到work数组中),直到不再能找到这样的进程为止。然后检查所有的进程,如果仍有未被化简的进程,则表明死锁已经产生。此时记录下发生死锁的进程编号。然后,为进一步明确哪些进程在哪些资源上发生死锁,给定一个进程入口点采用DFS搜索和次进程相关的所有进程。 为了能在每一步化简后显示当前进程资源的状况,定义了两个画图函数。一个是根据当前资源和进程的“占有”和“申请”状况,画出整体的资源分配图。另一个是在每次化简掉一个进程时删除和它相关的所有边。 程序在VC++6.0中调试、验收通过。
生产者和消费者问题是计算机同步互斥的经典问题,其中生产者负责将产品放入仓库,消费者负责从仓库中取出产品。仓库被视为临界区,只能同时允许一个生产者或消费者进入。这个问题的目标是实现生产者和消费者之间的同步和互斥。为了解决这个问题,可以采用解耦的方法,通过引入缓冲区来降低生产者和消费者之间的耦合度。生产者只需要将生产的数据添加到缓冲区,当缓冲区满时停止生产。消费者从缓冲区中读取数据,当缓冲区为空时停止消费。这样可以实现生产者和消费者之间的动态平衡。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* [操作系统经典问题之生产者消费者问题](https://blog.csdn.net/m0_43405302/article/details/121188406)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [操作系统经典 | 生产者与消费者问题](https://blog.csdn.net/chang466477509/article/details/121731151)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值