操作系统实验——典型同步问题模拟处理编程与实现
参考文章
-
读者——写者(读者优先):https://blog.csdn.net/lllllyt/article/details/80507085
-
读者——写者(写者优先):https://blog.csdn.net/lllllyt/article/details/80506884
-
生产者消费者问题:https://blog.csdn.net/lllllyt/article/details/80506508
1.问题描述
-
熟悉和运用 Linux 操作系统中系统调用 fork()的功能,编写程序调用 fork()创建两个子进程。父进程显示字符串‘Parent:’;两个子进分
别显示字符串‘Child1:’和‘Child2:’。多次运行此程序,观察屏幕显示的结果,并分析原因。
-
了解、熟悉和运用 Windows(或 Linux)操作系统同步机制及编程方法,针对典型的同步问题,譬如生产者‐消费者问题、读者优先
的读者‐写者问题、写者优先的读者‐写者问题、读者数限定的读者‐写者问题、哲学家就餐问题等(任选三个即可),编程模拟实现相
应问题的解决方案。
2. fork()
- 代码实现
#include <stdio.h>
#include <stdlib.h>
int main(){
int p1,p2;
while((p1=fork())==-1);
if (p1==0)
printf("Child1 \n");
else
{
while((p2=fork())==-1);
if (p2==0)
printf("Child2 \n");
else
printf("Parent \n");
}
return 0;
}
- 运行结果
3.生产者——消费者问题
- 思路
- 代码实现
# include <stdio.h>
# include <stdlib.h>
# include <time.h>
# include <sys/types.h>
# include <pthread.h>
# include <semaphore.h>
# include <string.h>
# include <unistd.h>
#define BUFFER_SIZE 5
//empty 同步信号量,表示剩余空间的数量
//full 同步信号量,表示产品的数量
//mutex 互斥信号量,实现对缓冲区的互斥访问
sem_t empty, full, mutex;
typedef int buffer_item;
//缓冲区
buffer_item buffer[BUFFER_SIZE];
int in, out;
// 记录产品的id
int id = 0;
//生产产品
int insert_item(buffer_item item) {
buffer[out] = item;
out = (out + 1) % BUFFER_SIZE;
return 0;
}
//消费产品
int remove_item(buffer_item *item) {
// 将buffer[in]移除,并将item填充进去
*item = buffer[in];
in = (in + 1) % BUFFER_SIZE;
return 0;
}
//生产者
void *producer(void* param) {
long threadid = (long)param;
while (1){
sem_wait(&empty);
sem_wait(&mutex);
//生产产品
insert_item(id);
sleep(6);
printf("ThreadId %ld : Producer produce product %d \n", threadid,id);
id++;
sem_post(&mutex);
sem_post(&full);
}
}
//消费者
void *consumer(void* param) {
long threadid = (long)param;
while (1){
sem_wait(&full);
sem_wait(&mutex);
//消费产品
int item;
remove_item(&item);
sleep(3);
printf("ThreadId %ld : Consumer consume product %d \n", threadid ,item);
sem_post(&mutex);
sem_post(&empty);
}
}
int main() {
//线程id
pthread_t tid[4];
//对mutex进行初始化
//第二个参数 不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享
//第三个参数 给出了信号量的初始值。
sem_init(&mutex, 0, 1);
sem_init(&empty, 0, BUFFER_SIZE);
sem_init(&full, 0, 0);
in = out = 0;
//两个生产者,两个消费者
pthread_create(&tid[0], NULL ,consumer, (void*)0);
pthread_create(&tid[1], NULL ,producer, (void*)1);
pthread_create(&tid[2], NULL ,consumer, (void*)2);
pthread_create(&tid[3], NULL, producer, (void*)3);
//用户输入q,结束进程
int c=0;
while (1){
c = getchar();
if (c=='q' || c=='Q'){
for (int i = 0; i < 4; ++i) {
pthread_cancel(tid[i]);
}
break;
}
}
//释放信号量
sem_destroy(&mutex);
sem_destroy(&empty);
sem_destroy(&full);
return 0;
}
-
实验结果
4.读者优先的读者-写者问题
- 代码实现
# include <stdio.h>
# include <stdlib.h>
# include <time.h>
# include <sys/types.h>
# include <pthread.h>
# include <semaphore.h>
# include <string.h>
# include <unistd.h>
// wrt(记录型信号量) 用于实现对文件的互斥访问
// mutex 用于对count变量的互斥访问
sem_t wrt, mutex;
//记录当前有几个读进程在访问文件
int readCount;
//读者
void* Reader(void* param) {
long threadid = (long)param;
while (1){
// P操作,各进程互斥地访问 mutex
sem_wait(&mutex);
readCount++;
if(readCount == 1)
sem_wait(&wrt);
// V操作
sem_post(&mutex);
printf("Thread %ld: is reading\n", threadid);
sleep(3);
sem_wait(&mutex);
readCount--;
if(readCount == 0)
sem_post(&wrt);
sem_post(&mutex);
}
}
//写者
void* Writer(void* param) {
long threadid = (long)param;
while (1){
sem_wait(&wrt);
printf("Thread %ld: is writing\n", threadid);
sleep(5);
sem_post(&wrt);
}
}
int main() {
sem_init(&mutex, 0, 1);
sem_init(&wrt, 0, 1);
readCount = 0;
pthread_t tid[4];
//两个写者、两个读者
pthread_create(&tid[0], NULL ,Writer, (void*)0);
pthread_create(&tid[1], NULL, Writer, (void*)1);
pthread_create(&tid[2], NULL ,Reader, (void*)2);
pthread_create(&tid[3], NULL ,Reader, (void*)3);
int c=0;
while (1){
c = getchar();
if (c=='q' || c=='Q'){
for (int i = 0; i < 4; ++i) {
pthread_cancel(tid[i]);
}
break;
}
}
//信号量销毁
sem_destroy(&mutex);
sem_destroy(&wrt);
return 0;
}
-
运行结果
- 写者线程先到达,开始运行,之后读者线程到达,对文件资源进行P操作,写者线程进入阻塞状态,读者线程开始运行。
5.写者优先的读者-写者问题
- 代码实现
/*
* 写者优先
*/
# include <stdio.h>
# include <stdlib.h>
# include <time.h>
# include <sys/types.h>
# include <pthread.h>
# include <semaphore.h>
# include <string.h>
# include <unistd.h>
// RWMutex 读写互斥
// mutex1 readCount互斥
// mutex2 writeCount互斥
// wrt 写者互斥
// mutex3的主要用处就是避免写者同时与多个读者进行竞争,读者中信号量RWMutex比mutex3先释放,则一旦有写者,写者可马上获得资源。
sem_t RWMutex, mutex1, mutex2, mutex3, wrt;
//用于记录正在等待的写者的数目
int writeCount, readCount;
//读者
void* Reader(void* param) {
long threadid = (long)param;
while (1){
//p操作
sem_wait(&mutex3);
sem_wait(&RWMutex);
sem_wait(&mutex2);
readCount++;
if(readCount == 1)
sem_wait(&wrt);
//v操作
sem_post(&mutex2);
sem_post(&RWMutex);
sem_post(&mutex3);
sleep(3);
printf("Thread %ld: is reading\n", threadid);
sem_wait(&mutex2);
readCount--;
if(readCount == 0)
sem_post(&wrt);
sem_post(&mutex2);
}
}
//写者
void* Writer(void* param) {
long threadid = (long)param;
while (1){
sem_wait(&mutex1);
writeCount++;
if(writeCount == 1){
sem_wait(&RWMutex);
}
sem_post(&mutex1);
sem_wait(&wrt);
sleep(5);
printf("Thread %ld: is writing\n", threadid );
sem_post(&wrt);
sem_wait(&mutex1);
writeCount--;
if(writeCount == 0) {
sem_post(&RWMutex);
}
sem_post(&mutex1);
}
}
int main() {
//初始化信号量
sem_init(&mutex1, 0, 1);
sem_init(&mutex2, 0, 1);
sem_init(&mutex3, 0, 1);
sem_init(&wrt, 0, 1);
sem_init(&RWMutex, 0, 1);
readCount = writeCount = 0;
pthread_t tid[4];
//两个读者,两个写者
pthread_create(&tid[0], NULL ,Reader, (void*)0);
pthread_create(&tid[1], NULL ,Reader, (void*)1);
pthread_create(&tid[2], NULL ,Writer, (void*)2);
pthread_create(&tid[3], NULL, Writer, (void*)3);
int c=0;
while (1){
c = getchar();
if (c=='q' || c=='Q'){
for (int i = 0; i < 4; ++i) {
pthread_cancel(tid[i]);
}
break;
}
}
//信号量销毁
sem_destroy(&mutex1);
sem_destroy(&mutex2);
sem_destroy(&mutex3);
sem_destroy(&RWMutex);
sem_destroy(&wrt);
return 0;
}
-
实验结果
6.读者数量有限的读者-写者问题
- 思路
添加一个信号量,初始化为5,当读者进入时,进行P操作。退出时,进行V操作。
-
代码实现
# include <stdio.h> # include <stdlib.h> # include <time.h> # include <sys/types.h> # include <pthread.h> # include <semaphore.h> # include <string.h> # include <unistd.h> // wrt(记录型信号量) 用于实现对文件的互斥访问 // mutex 用于对count变量的互斥访问 sem_t wrt, mutex, readerNum; //记录当前有几个读进程在访问文件 int readCount; //读者 void* Reader(void* param) { long threadid = (long)param; while (1){ //p操作 sem_wait(&readerNum); sem_wait(&mutex); readCount++; if(readCount == 1) sem_wait(&wrt); //V操作 sem_post(&mutex); printf("Thread %ld: is reading\n", threadid); sleep(3); sem_wait(&mutex); readCount--; if(readCount == 0) sem_post(&wrt); sem_post(&mutex); sem_post(&readerNum); } } //写者 void* Writer(void* param) { long threadid = (long)param; while (1){ sem_wait(&wrt); printf("Thread %ld: is writing\n", threadid); sleep(5); sem_post(&wrt); } } int main() { //初始化信号量 //读者数量限定为5 sem_init(&readerNum,0,5); sem_init(&mutex, 0, 1); sem_init(&wrt, 0, 1); readCount = 0; pthread_t tid[10]; //创建6个读者线程,观察第六个读者能否运行 for (int i = 0; i < 6; ++i) { pthread_create(&tid[i], NULL ,Reader, (void*)i); } pthread_create(&tid[7], NULL, Writer, (void*)6); pthread_create(&tid[8], NULL, Writer, (void*)7); int c=0; while (1){ c = getchar(); if (c=='q' || c=='Q'){ for (int i = 0; i < 8; ++i) { pthread_cancel(tid[i]); } break; } } //信号量销毁 sem_destroy(&mutex); sem_destroy(&wrt); return 0; }
-
实验结果
- 读者数量限制为5,因此只有5个读者线程可以运行,其余的读者线程和写者线程进入阻塞状态。
7.哲学家就餐问题
-
思路:假如五位哲学家同时饥饿而各自拿起左边的筷子时,就会使五个信号量chopstick均为0,当他们再试图去拿右边的筷子时,都将因无筷子可拿而无限等待。进入死锁状态。因此我们限定仅当一个哲学家左右两支筷子都可用时才允许他抓起筷子。
-
代码实现
# include <stdio.h>
# include <stdlib.h>
# include <time.h>
# include <sys/types.h>
# include <pthread.h>
# include <semaphore.h>
# include <string.h>
# include <unistd.h>
//mutex互斥的取筷子
sem_t chopstick[5],mutex;
void *eat_think(void *arg)
{
int phi = (int)arg;
while (1){
sem_wait(&mutex);
sem_wait(&chopstick[phi]); //拿左
sem_wait(&chopstick[(phi+1)%5]); //拿右
printf("Philosopher %d fetches chopstick %d\n",phi,phi);
printf("Philosopher %d fetches chopstick %d\n",phi,phi+1);
sem_post(&mutex);
sleep(5); //吃饭
printf("Philosopher %d is eating \n",phi);
sem_post(&chopstick[phi]);
sem_post(&chopstick[phi+1]);
printf("Philosopher %d release chopstick %d\n", phi, phi);
printf("Philosopher %d release chopstick %d\n", phi, phi+1);
//思考
sleep(3);
}
}
int main() {
//线程id
pthread_t tid[5];
sem_init(&mutex,0,1);
for (int i = 0; i < 5; ++i) {
sem_init(&chopstick[i],0,1);
}
// sem_init(&mutex, 0, 1);
for (int i = 0; i < 5; ++i) {
pthread_create(&tid[i] ,NULL, eat_think,(void *)i);
}
int c=0;
while (1){
c = getchar();
if (c=='q' || c=='Q'){
for (int i = 0; i < 4; ++i) {
pthread_cancel(tid[i]);
}
break;
}
}
return 0;
}
- 实验结果