操作系统实验:同步问题

Task 1:
实验要求:
通过fork的方式,产生4个进程P1,P2,P3,P4,每个进程打印输出自己的名字,例如P1输出“I am the process P1”。要求P1最先执行,P2、P3互斥执行,P4最后执行。通过多次测试验证实现是否正确。

程序代码:

#include 
#include 
#include 
#include 
#include 

sem_t *mySem = NULL;		//进程2和进程3互斥信号量
sem_t *mySem2 = NULL;	//进程2结束信号量
sem_t *mySem3 = NULL;	//进程3结束信号量
void *createP2(void *arg) {	
   pid_t  p2;
   sem_wait(mySem);
   while((p2=fork())==-1);
   if(p2>0)
	printf("I am the process P2!\n");	
   sem_post(mySem);
   sem_post(mySem2);
   return NULL;
}
void *createP3(void *arg) {
   pid_t  p3;
   sem_wait(mySem);
   while((p3=fork())==-1);
   if(p3>0)
	printf("I am the process P3!\n");	
   sem_post(mySem);
   sem_post(mySem3);
   return NULL;
}
void *createP4(void *arg) {
   pid_t  p4;
   sem_wait(mySem2);
   sem_wait(mySem3);
   while((p4=fork())==-1);
   if(p4>0)
	printf("I am the process P4!\n");	
   sem_post(mySem2);
   sem_post(mySem3);
   return NULL;
}
int main(int argc, char* argv[])
{
   pid_t  p1;
   pthread_t pp2, pp3, pp4;
   while((p1=fork())==-1);
   if(p1>0){
	printf("I am the process P1!\n");
	mySem = sem_open("mySem", O_CREAT, 0666, 1); 
	mySem2 = sem_open("mySem2", O_CREAT, 0666, 0); 
	mySem3 = sem_open("mySem3", O_CREAT, 0666, 0); 
	pthread_create(&pp2, NULL, createP2, NULL);
	pthread_create(&pp3, NULL, createP3, NULL);
	pthread_create(&pp4, NULL, createP4, NULL);
	pthread_join(pp2, NULL);
	pthread_join(pp3, NULL);
	pthread_join(pp4, NULL);
	sem_close(mySem);	//线程结束
	sem_close(mySem2);
	sem_close(mySem3);
	sem_unlink("mySem");
	sem_unlink("mySem2");
	sem_unlink("mySem3");
   }
   return 0;
}

代码解析:
主函数产生进程P1,在进程P1中通过三个线程PP2、PP3、PP4分别执行子函数createP2、createP3、createP4产生3个进程P2、P3、P4。
设置三个信号量: mySem(进程2和进程3互斥信号量)、mySem2(进程2结束信号量)、mySem3(进程3结束信号量)用来实现P2、P3互斥执行,P4最后执行。

实验结果:
操作系统实验:同步问题_第1张图片
代码执行结果顺序为:P1、P3、P2、P4,符合实验要求。

原理解析:
进程前趋图为:
操作系统实验:同步问题_第2张图片
P1为在主函数中直接通过过fork的方式产生,最先执行;

void *createP2(void *arg) {	
   pid_t  p2;
   sem_wait(mySem);
   while((p2=fork())==-1);
   if(p2>0)
	printf("I am the process P2!\n");	
   sem_post(mySem);
   sem_post(mySem2);
   return NULL;
}
void *createP3(void *arg) {
   pid_t  p3;
   sem_wait(mySem);
   while((p3=fork())==-1);
   if(p3>0)
	printf("I am the process P3!\n");	
   sem_post(mySem);
   sem_post(mySem3);
   return NULL;
}

由上述子函数可知: 两个线程同时阻塞等待sem_wait(mySem),则P2、P3互斥执行;

void *createP4(void *arg) {
   pid_t  p4;
   sem_wait(mySem2);
   sem_wait(mySem3);
   while((p4=fork())==-1);
   if(p4>0)
	printf("I am the process P4!\n");	
   sem_post(mySem2);
   sem_post(mySem3);
   return NULL;
}

由子函数createP4可知: 必须等待sem_wait(mySem2)、sem_wait(mySem3);都实现后,才可创建进程P4,P4最后执行。

Task 2:
实验要求:
火车票余票数ticketCount 初始值为1000,有一个售票线程,一个退票线程,各循环执行多次。添加同步机制,使得结果始终正确。要求多次测试添加同步机制前后的实验效果。(说明:为了更容易产生并发错误,可以在适当的位置增加一些pthread_yield(),放弃CPU,并强制线程频繁切换。)

程序代码:

#include 
#include 
#include 
#include 
#include 
#include 
int pthread_yield(void);
int ticketCount = 1000;
sem_t *mySem = NULL;
void *ticket(void *arg) {	//售票
   int temp;
   while(1){
	if(ticketCount>0){
		sem_wait(mySem);	//同步操作
		temp=ticketCount;
		pthread_yield();
		temp=temp-1;
		pthread_yield();
		ticketCount=temp;		
		sleep(1);
		printf("售票1张,现有票数:%d!\n",ticketCount);
		sem_post(mySem);	 //同步操作
		}	
	}
   return NULL;
}
void *refund(void *arg) {	//退票
   int temp;
   while(1){
	if(ticketCount<1000){
		sem_wait(mySem);	 //同步操作
		temp=ticketCount;
		pthread_yield();
		temp=temp+1;
		pthread_yield();
		ticketCount=temp;		
		sleep(1);
		printf("退票1张,现有票数:%d!\n",ticketCount);
		sem_post(mySem);  //同步操作
		}	
	}
   return NULL;
}
int main(void)
{
   pthread_t p1, p2;
   printf("现有票数:%d张,售票退票线程开始!\n",ticketCount);
   mySem = sem_open("mySem", O_CREAT, 0666, 1); 
   pthread_create(&p1, NULL, ticket, NULL);
   pthread_create(&p2, NULL, refund, NULL);	
   pthread_join(p1, NULL);
   pthread_join(p2, NULL);
   sem_close(mySem);//线程结束
   sem_unlink("mySem");//主程序结尾
   return 0;
}

代码解析:
注:
带有“//同步操作”的程序代码行为实现同步机制所添加,在不想要同步前应注释掉;
主函数产生两个线程P1、P2分别执行子函数ticke(售票)、refund(退票)用来售票、退票操作。程序代码应注意:在没有售出票以前,不允许退票。在售票1000张后,不在允许售票。售票、退票两个线程同时执行,并在适当的位置增加一些pthread_yield(),放弃CPU,强制线程频繁切换。
通过设置信号量mySem用来实现同步机制,即不能同时对余票量ticketCount进行写操作。

实验结果:
添加同步前:
操作系统实验:同步问题_第3张图片

添加同步后:
操作系统实验:同步问题_第4张图片
操作系统实验:同步问题_第5张图片
操作系统实验:同步问题_第6张图片
操作系统实验:同步问题_第7张图片

实验结果解析:
添加同步前,两个线程同时执行,当售票一张后,还未打印余票量ticketCount时,退票线程又退票一张,使得余票量ticketCount又加一,打印余票量时ticketCount为退票执行后,则打印出结果为:售票1张,现有票数:1000!;明显结果错误!因此,未添加同步前,两个线程可同时对余票量ticketCount进行读写操作,则导致显示结果不可信,数据不准确!
添加同步后,两个线程共享信号量mysem,互斥执行,即当售票时,退票阻塞等待;即当退票时,售票阻塞等待。只有当售票完全结束后,余票量ticketCount变化后,打印余票量ticketCount后,才可进行下一线程操作;退票时也相同。因此,添加同步后,两个线程不可同时对余票量ticketCount进行读写操作,则数据具有准确性!退票,售票进程是处理机随机调度,不具有可预测性!当退票数达到1000后,不可在进行退票操作,符合现实情况,待有票售出后,才可继续进行退票操作(结果演示请看添加同步后第3张截图)。

Task3:
实验要求:
一个生产者一个消费者线程同步。设置一个线程共享的缓冲区, char buf[10]。一个线程不断从键盘输入字符到buf,一个线程不断的把buf的内容输出到显示器。要求输出的和输入的字符和顺序完全一致。(在输出线程中,每次输出睡眠一秒钟,然后以不同的速度输入测试输出是否正确)。要求多次测试添加同步机制前后的实验效果。

程序代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

char buffer[10];
int i=0,j=0;
sem_t *full = NULL;
sem_t *empty = NULL;
void *worker1(void *arg) {	//生产者
   while(1){
	sem_wait(empty);
	scanf("%c",&buffer[j]);j++;
	sleep(1);
	if(j>=10)j%=10;
	sem_post(full);
	}
   return NULL;
}
void *worker2(void *arg) {	//消费者
   while(1){
	sem_wait(full);
	printf("输出:%c\n",buffer[i]);i++;
	sleep(1);
	if(i>=10)i%=10;
	sem_post(empty);
	}
   return NULL;
}
int main(int argc, char *argv[])
{
   pthread_t p1, p2;
   full = sem_open("full", O_CREAT, 0666, 0); 
   empty = sem_open("empty", O_CREAT, 0666, 10); 
   pthread_create(&p1, NULL, worker1, NULL);
   pthread_create(&p2, NULL, worker2, NULL);
   pthread_join(p1, NULL);
   pthread_join(p2, NULL);
   sem_close(full);//线程结束
   sem_close(empty);//线程结束
   sem_unlink("full");//主程序结尾
   sem_unlink("empty");//主程序结尾
   return 0;
}

代码解析:
主函数产生两个线程P1、P2分别执行子函数worker1(生产者)、worker2(消费者)用来往buffer缓冲区中读入、读出数据操作。设置一个共享信号量full,用来表示buffer缓冲区中数据个数;设置一个共享信号量empty,用来表示buffer缓冲区中空闲位置个数;
需注意:在没有数据以前,不允许读出,worker2()函数阻塞等待;在数据存满以后,不允许读入,worker1()函数阻塞等待。

实验结果:
第一次测试:
操作系统实验:同步问题_第8张图片
第二次测试:
操作系统实验:同步问题_第9张图片
第三次测试(输入数据大于10):
操作系统实验:同步问题_第10张图片
第四次测试(连续输入):
操作系统实验:同步问题_第11张图片
实验结果解析:
一个生产者一个消费者线程共享的一个缓冲区:char buf[10];一个线程不断从键盘输入字符到buf,一个线程不断的把buf的内容输出到显示器。在实验结果截图中:“输出:”前为输入的字符,后为输出的字符。
empty的初始值为10,full的初始值为0,输入字符最多可以连续读入10个,其他的在I/O缓冲区等待输入;当full的值大于0时,输出线程便可进行输出,每输出一个字符便会post一个empty信号量,此时输入线程接收到empty信号量便可开始从I/O缓冲区继续读取数据。根据实验结果可知:当输入数据很长或间断输入时,都可保证输出的和输入的字符和顺序完全一致,实验结果准确。

Task4:
实验要求:
进程通信问题。阅读并运行共享内存、管道、消息队列三种机制的代码
(参见https://www.cnblogs.com/Jimmy1988/p/7706980.html;https://www.cnblogs.com/Jimmy1988/p/7699351.html;https://www.cnblogs.com/Jimmy1988/p/7553069.html )

实验测试:
a)通过实验测试,验证共享内存的代码中,receiver能否正确读出sender发送的字符串?如果把其中互斥的代码删除,观察实验结果有何不同?如果在发送和接收进程中打印输出共享内存地址,他们是否相同,为什么?

程序代码:

/*
 * Filename: Sender.c
 * Description: 
 */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    key_t  key;
    int shm_id;
    int sem_id;
    int value = 0;
    //1.Product the key
    key = ftok(".", 0xFF);
    //2. Creat semaphore for visit the shared memory
    sem_id = semget(key, 1, IPC_CREAT|0644);
    if(-1 == sem_id)
    {
        perror("semget");
        exit(EXIT_FAILURE);
    }
    //3. init the semaphore, sem=0
    if(-1 == (semctl(sem_id, 0, SETVAL, value)))
    {
        perror("semctl");
        exit(EXIT_FAILURE);
    }
    //4. Creat the shared memory(1K bytes)
    shm_id = shmget(key, 1024, IPC_CREAT|0644);
    if(-1 == shm_id)
    {
        perror("shmget");
        exit(EXIT_FAILURE);
    }
    //5. attach the shm_id to this process
    char *shm_ptr;
    shm_ptr = shmat(shm_id, NULL, 0);
    if(NULL == shm_ptr)
    {
        perror("shmat");
        exit(EXIT_FAILURE);
    }
    //6. Operation procedure
    struct sembuf sem_b;
    sem_b.sem_num = 0;      //first sem(index=0)
    sem_b.sem_flg = SEM_UNDO;
    sem_b.sem_op = 1;           //Increase 1,make sem=1
    while(1)
    {
        if(0 == (value = semctl(sem_id, 0, GETVAL)))
        {
            printf("\nNow, snd message process running:\n");
            printf("\tInput the snd message:  ");
            scanf("%s", shm_ptr);

            if(-1 == semop(sem_id, &sem_b, 1))
            {
                perror("semop");
                exit(EXIT_FAILURE);
            }
        }
        //if enter "end", then end the process
        if(0 == (strcmp(shm_ptr ,"end")))
        {
            printf("\nExit sender process now!\n");
            break;
        }
    }
    shmdt(shm_ptr);
    return 0;
}

/*
 * Filename: Receiver.c
 * Description: 
 */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    key_t  key;
    int shm_id;
    int sem_id;
    int value = 0;
    //1.Product the key
    key = ftok(".", 0xFF);
    //2. Creat semaphore for visit the shared memory
    sem_id = semget(key, 1, IPC_CREAT|0644);
    if(-1 == sem_id)
    {
        perror("semget");
        exit(EXIT_FAILURE);
    }
    //3. init the semaphore, sem=0
    if(-1 == (semctl(sem_id, 0, SETVAL, value)))
    {
        perror("semctl");
        exit(EXIT_FAILURE);
    }
    //4. Creat the shared memory(1K bytes)
    shm_id = shmget(key, 1024, IPC_CREAT|0644);
    if(-1 == shm_id)
    {
        perror("shmget");
        exit(EXIT_FAILURE);
    }
    //5. attach the shm_id to this process
    char *shm_ptr;
    shm_ptr = shmat(shm_id, NULL, 0);
    if(NULL == shm_ptr)
    {
        perror("shmat");
        exit(EXIT_FAILURE);
    }
    //6. Operation procedure
    struct sembuf sem_b;
    sem_b.sem_num = 0;      //first sem(index=0)
    sem_b.sem_flg = SEM_UNDO;
    sem_b.sem_op = -1;           //Increase 1,make sem=1
    while(1)
    {
        if(1 == (value = semctl(sem_id, 0, GETVAL)))
        {
            printf("\nNow, receive message process running:\n");
            printf("\tThe message is : %s\n", shm_ptr);

            if(-1 == semop(sem_id, &sem_b, 1))
            {
                perror("semop");
                exit(EXIT_FAILURE);
            }
        }
        //if enter "end", then end the process
        if(0 == (strcmp(shm_ptr ,"end")))
        {
            printf("\nExit the receiver process now!\n");
            break;
        }
    }
    shmdt(shm_ptr);
    //7. delete the shared memory
    if(-1 == shmctl(shm_id, IPC_RMID, NULL))
    {
        perror("shmctl");
        exit(EXIT_FAILURE);
    }
    //8. delete the semaphore
    if(-1 == semctl(sem_id, 0, IPC_RMID))
    {
        perror("semctl");
        exit(EXIT_FAILURE);
    }
    return 0;
}

代码执行:
打开两个终端,分别执行编译命令:
gcc -o Sender Sender.c -lpthread
gcc -o Receiver Receiver.c -lpthread

实验结果:
操作系统实验:同步问题_第12张图片
操作系统实验:同步问题_第13张图片

实验结果解析:
可见Sender进程发出的消息Receiver进程准确无误的接收;但Sender读入信息时用的是scanf("%s", shm_ptr)机制,遇到空格自动结束,则出现上述截图效果。

删除互斥的代码:
代码变化处仅以下两个地方:
Sender.c
操作系统实验:同步问题_第14张图片
Receiver.c
操作系统实验:同步问题_第15张图片

代码执行:
打开两个终端,分别执行编译命令:
gcc -o Sender2 Sender2.c -lpthread
gcc -o Receiver2 Receiver2.c -lpthread

实验结果:
操作系统实验:同步问题_第16张图片
操作系统实验:同步问题_第17张图片
操作系统实验:同步问题_第18张图片
操作系统实验:同步问题_第19张图片
实验结果解析:
可见Sender进程发出的消息Receiver进程接收出现错误;
当Sender进程未发送信息前,Receiver进程一直输出空信息;
当Sender进程发送信息后,Receiver进程一直输出刚接收到的信息;
因Sender读入信息时用的是scanf("%s", shm_ptr)机制,遇到空格自动结束,则读入“ I am YSS!”时,“YSS!”会覆盖前面的消息,Receiver进程没有接收到“ I am ”。

在发送和接收进程中打印输出共享内存地址:
代码变动:
只需分别在Sender、Receiver代码中添加:
printf(“共享内存地址:%p\n”,shm_ptr);
(具体代码请看Sender3.c、Receiver3.c)

实验结果:
在这里插入图片描述在这里插入图片描述
可见共享内存地址不同。

原因分析:
共享内存映射函数shmat():
作用:将共享内存空间挂载到进程中
头文件:#include
函数原型:
void *shmat(int shmid, const void *shmaddr, int shmflg)
参数:
shmid : shmget()返回值
shmaddr: 共享内存的映射地址,一般为0(由系统自动分配地址)
shmflg : 访问权限和映射条件
在执行共享内存映射函数shm_ptr(shm_id, NULL, 0)时:参数shmaddr为NULL,则由系统自动分配地址,则两个进程共享内存地址可能不同。

实验测试:
b)有名管道和无名管道通信系统调用是否已经实现了同步机制?通过实验验证,发送者和接收者如何同步的。比如,在什么情况下,发送者会阻塞,什么情况下,接收者会阻塞?
有名管道:
程序代码:

/*
 *File: fifo_send.c
 */
 
#include 
#include 
#include 
#include 
#include 
#include 

#define FIFO "/tmp/my_fifo"
int main()
{
    char buf[] = "hello,world";
    //`. check the fifo file existed or not
    int ret;
    ret = access(FIFO, F_OK);
    if(ret == 0)    //file /tmp/my_fifo existed
    {
        system("rm -rf /tmp/my_fifo");
    }
    //2. creat a fifo file
    if(-1 == mkfifo(FIFO, 0766))
    {
        perror("mkfifo");
        exit(EXIT_FAILURE);
    }
    //3.Open the fifo file
    int fifo_fd;
    fifo_fd = open(FIFO, O_WRONLY);
    if(-1 == fifo_fd)
    {
        perror("open");
        exit(EXIT_FAILURE);
    }
    //4. write the fifo file
    int num = 0;
    num = write(fifo_fd, buf, sizeof(buf));
    if(num < sizeof(buf))
    {
        perror("write");
        exit(EXIT_FAILURE);
    }
    printf("write the message ok!\n");
    close(fifo_fd);
    return 0;
}

/*
 *File: fifo_rcv.c
 */
 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define FIFO "/tmp/my_fifo"
int main()
{
    char buf[20] ;
    memset(buf, '\0', sizeof(buf));
    //`. check the fifo file existed or not
    int ret;
    ret = access(FIFO, F_OK);
    if(ret != 0)    //file /tmp/my_fifo existed
    {
        fprintf(stderr, "FIFO %s does not existed", FIFO);
        exit(EXIT_FAILURE);
    }
    //2.Open the fifo file
    int fifo_fd;
    fifo_fd = open(FIFO, O_RDONLY);
    if(-1 == fifo_fd)
    {
        perror("open");
        exit(EXIT_FAILURE);

    }
    //4. read the fifo file
    int num = 0;
    num = read(fifo_fd, buf, sizeof(buf));
    printf("Read %d words: %s\n", num, buf);
    close(fifo_fd);
    return 0;
}

实验结果:
在这里插入图片描述在这里插入图片描述
实验结果分析:
有名管道通信系统调用已经实现了同步机制。
阻塞情况见下表:操作系统实验:同步问题_第20张图片

无名管道:
程序代码:

/*
 * Filename: pipe.c
 */
 
#include 
#include      //for pipe()
#include      //for memset()
#include      //for exit()

int main()
{
    int fd[2];
    char buf[20];
    if(-1 == pipe(fd))
    {
        perror("pipe");
        exit(EXIT_FAILURE);
    }
    write(fd[1], "hello,world", 12);
    memset(buf, '\0', sizeof(buf));

    read(fd[0], buf, 12);
    printf("The message is: %s\n", buf);
    return 0;
}

实验结果:
在这里插入图片描述

实验结果分析:
无名管道通信系统调用已经实现了同步机制。
无名管道存储文件描述符:
操作系统实验:同步问题_第21张图片
阻塞情况见下表:
操作系统实验:同步问题_第22张图片
实验测试:
c)消息通信系统调用是否已经实现了同步机制?通过实验验证,发送者和接收者如何同步的。比如,在什么情况下,发送者会阻塞,什么情况下,接收者会阻塞?
程序代码:
client.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define BUF_SIZE 128
//Rebuild the strcut (must be)
struct msgbuf
{
    long mtype;
    char mtext[BUF_SIZE];
};

int main(int argc, char *argv[])
{
    //1. creat a mseg queue
    key_t key;
    int msgId;
    printf("THe process(%s),pid=%d started~\n", argv[0], getpid());
    key = ftok(".", 0xFF);
    msgId = msgget(key, IPC_CREAT|0644);
    if(-1 == msgId)
    {
        perror("msgget");
        exit(EXIT_FAILURE);
    }
    //2. creat a sub process, wait the server message
    pid_t pid;
    if(-1 == (pid = fork()))
    {
        perror("vfork");
        exit(EXIT_FAILURE);
    }
    //In child process
    if(0 == pid)
    {
        while(1)
        {
            alarm(0);
            alarm(100);     //if doesn't receive messge in 100s, timeout & exit
            struct msgbuf rcvBuf;
            memset(&rcvBuf, '\0', sizeof(struct msgbuf));
            msgrcv(msgId, &rcvBuf, BUF_SIZE, 2, 0);                
            printf("Server said: %s\n", rcvBuf.mtext);
        }  
        exit(EXIT_SUCCESS);
    }
    else    //parent process
    {
        while(1)
        {
            usleep(100);
            struct msgbuf sndBuf;
            memset(&sndBuf, '\0', sizeof(sndBuf));
            char buf[BUF_SIZE] ;
            memset(buf, '\0', sizeof(buf));        
            printf("\nInput snd mesg: ");
            scanf("%s", buf);         
            strncpy(sndBuf.mtext, buf, strlen(buf)+1);
            sndBuf.mtype = 1;
            if(-1 == msgsnd(msgId, &sndBuf, strlen(buf)+1, 0))
            {
                perror("msgsnd");
                exit(EXIT_FAILURE);
            }           
            //if scanf "end~", exit
            if(!strcmp("end~", buf))
                break;
        }       
        printf("THe process(%s),pid=%d exit~\n", argv[0], getpid());
    }
    return 0;
}

server.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define BUF_SIZE 128
//Rebuild the strcut (must be)
struct msgbuf
{
    long mtype;
    char mtext[BUF_SIZE];
};

int main(int argc, char *argv[])
{
    //1. creat a mseg queue
    key_t key;
    int msgId;
    key = ftok(".", 0xFF);
    msgId = msgget(key, IPC_CREAT|0644);
    if(-1 == msgId)
    {
        perror("msgget");
        exit(EXIT_FAILURE);
    }
    printf("Process (%s) is started, pid=%d\n", argv[0], getpid());
    while(1)
    {
        alarm(0);
        alarm(600);     //if doesn't receive messge in 600s, timeout & exit
        struct msgbuf rcvBuf;
        memset(&rcvBuf, '\0', sizeof(struct msgbuf));
        msgrcv(msgId, &rcvBuf, BUF_SIZE, 1, 0);                
        printf("Receive msg: %s\n", rcvBuf.mtext);     
        struct msgbuf sndBuf;
        memset(&sndBuf, '\0', sizeof(sndBuf));
        strncpy((sndBuf.mtext), (rcvBuf.mtext), strlen(rcvBuf.mtext)+1);
        sndBuf.mtype = 2;
        if(-1 == msgsnd(msgId, &sndBuf, strlen(rcvBuf.mtext)+1, 0))
        {
            perror("msgsnd");
            exit(EXIT_FAILURE);
        }       
        //if scanf "end~", exit
        if(!strcmp("end~", rcvBuf.mtext))
             break;
    }    
    printf("THe process(%s),pid=%d exit~\n", argv[0], getpid());
    return 0;
}

代码解析:
server.c:
等待接收客户端发送的数据,若时间超出600s,则自动exit;
当收到信息后,打印接收到的数据;并原样的发送给客户端,由客户端显示。

client.c:
启动两个进程(父子进程),父进程用于发送数据,子进程接收由server发送的数据;
发送数据:由使用者手动输入信息,回车后发送;当写入“end~”后,退出本进程。
接收数据:接收由Server端发送的数据信息,并打印。

实验结果:
操作系统实验:同步问题_第23张图片
操作系统实验:同步问题_第24张图片
实验结果分析:
消息通信系统调用已经实现了同步机制。
阻塞机制:当client不阻塞时,接受server消息的时候会一直打印空消息;当server不阻塞时,server会一直接受空消息并转发给client。

Task5:
实验要求:
阅读Pintos操作系统,找到并阅读进程上下文切换的代码,说明实现的保存和恢复的上下文内容以及进程切换的工作流程。

内容较多,请点击以下链接:
http://www.cnblogs.com/laiy/p/pintos_project1_thread.html
https://wenku.baidu.com/view/9e94430671fe910ef02df884.html

如需了解更多知识,可点击以下链接:
https://github.com/yuanshaosui/OS/tree/master/实验三

你可能感兴趣的:(操作系统实验:同步问题)