实验三 同步与通信

本文深入探讨了操作系统实验中的关键概念,包括进程同步与通信、共享内存、管道通信、消息队列及上下文切换机制。通过具体实验代码和结果,详细解析了同步机制的重要性,展示了信号量、有名和无名管道在进程间通信的应用,以及消息队列的同步特性。同时,揭示了Pintos操作系统中上下文切换的实现细节。

实验三 同步与通信

16281042 李许增
操作系统:arch Linux

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

在这里插入图片描述

实验代码(fork.c)
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
sem_t *a_sem, *b_sem, *c_sem, *d_sem;
int main()
{
    a_sem = sem_open("asem", O_CREAT, 0666, 0);
    b_sem = sem_open("bsem", O_CREAT, 0666, 0);
    c_sem = sem_open("csem", O_CREAT, 0666, 0);
    pid_t fork_pid;//fork函数返回值
    printf("我是进程P1\n");
    sleep(1);
    sem_post(a_sem);
    fork_pid = fork();
    if(fork_pid == 0)
    {
        sem_wait(a_sem);
        printf("我是进程P2\n");
        sleep(1);
        sem_post(a_sem);
        sem_post(b_sem);
    }
    else
    {
        fork_pid = fork();
        if(fork_pid == 0)
        {
            sem_wait(a_sem);
            printf("我是进程P3\n");
            sleep(1);
            sem_post(a_sem);
            sem_post(c_sem);
        }
        else
        {
            fork_pid = fork();
            if(fork_pid == 0)
            {
                sem_wait(b_sem);
                sem_wait(c_sem);
                printf("我是进程P4\n");
                sleep(1);
                sem_post(b_sem);
                sem_post(c_sem);
            }
            else
            {}
        }
    }
    sem_close(a_sem);
    sem_close(b_sem);
    sem_close(c_sem);
    unlink("asem");
    unlink("bsem");
    unlink("csem");
    return 0;
}
实验结果

在这里插入图片描述

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

首先进行不添加信号量控制进行测试:

实验代码(ticket.c)
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int ticketcount = 1000;
int temp;
void *saller() {
    int i = 500;
    while(i > 0)
    {
        temp = ticketcount;
        pthread_yield();
        temp = temp - 1;
        pthread_yield();
        ticketcount = temp;
        i--;
    }
    return NULL;
}

void *refund_ticket(){
    int i = 500;
    while(i > 0)
    {
        temp = ticketcount;
        pthread_yield();
        temp = temp + 1;
        pthread_yield();
        ticketcount = temp;
        i--;
    }
    return NULL;
}

int main()
{
	pthread_t p1, p2;
	pthread_create(&p1, NULL, saller, NULL);
	pthread_create(&p2, NULL, refund_ticket, NULL);
	pthread_join(p1, NULL);
	pthread_join(p2, NULL);
	printf("火车票余量 : %d\n", ticketcount);
	return 0;
}
不添加信号量实验结果

我们能再函数体内设置退票人数为500,购票人数为500,则最终票的数目结果应该为1000
由于进程并发执行对与共享变量temp的操作有冲突,所以会出现错误,ticketcount输出不为1000
在这里插入图片描述
进行添加信号量的测试

实验代码(ticket_sem.c)
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int ticketcount = 1000;
int temp;
sem_t * mysem = NULL;

void *saller() {
    int i = 500;
    while(i > 0)
    {
        sem_wait(mysem);
        temp = ticketcount;
        pthread_yield();
        temp = temp - 1;
        pthread_yield();
        ticketcount = temp;
        i--;
        sem_post(mysem);
    }
    return NULL;
}

void *refund_ticket(){
    int i = 500;
    while(i > 0)
    {
        sem_wait(mysem);
        temp = ticketcount;
        pthread_yield();
        temp = temp + 1;
        pthread_yield();
        ticketcount = temp;
        i--;
        sem_post(mysem);
    }
    return NULL;
}

int main()
{
	mysem = sem_open("csem",O_CREAT,0666,1);
	pthread_t p1, p2;
	pthread_create(&p1, NULL, saller, NULL);
	pthread_create(&p2, NULL, refund_ticket, NULL);
	pthread_join(p1, NULL);
	pthread_join(p2, NULL);
	printf("火车票余量 : %d\n", ticketcount);
	sem_close(mysem);
	unlink("csem");
	return 0;
}

当我们互斥添加信号量进行控制后输出正常

实验结果:

在这里插入图片描述

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

首先进行不添加信号量的测试
实验代码(buff_share.c):

#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
char buff[10];
int i = 0, j = 9;
//sem_t * mysem = NULL;
void *work1()
{
	while(1)
    {
        scanf("%c\n",&buff[i]);
        i++;
        i = i%10;
    }
	return NULL;
}
void *work2()
{
	while(1)
	{
        if(((j + 1)% 10) != i)
        {
            printf("我是输出:%c\n",buff[(j + 1) % 10]);
            sleep(1);
            j++;
            j = j%10;
        }
	}
	return NULL;
}

int main(int argc, char *argv[])
{
	//mysem = sem_open("csem",O_CREAT,0666,1);
	pthread_t p1, p2;
	pthread_create(&p1, NULL, work1, NULL);
	pthread_create(&p2, NULL, work2, NULL);
	pthread_join(p1, NULL);
	pthread_join(p2, NULL);
	//sem_close(mysem);
	//unlink("csem");
	return 0;
}

由于没有添加信号量导致如果输入快于输出,且比输出快设置的数组大小(本代码中为10个字符),那么原来存在于数组中的字符在没有数出来的情况下会被后面读进的字符覆盖掉。

实验结果:

我们可以看出在q之后的"ertyuiopa"等字符被覆盖
在这里插入图片描述
正常速度输入:
在这里插入图片描述
下面进行添加信号量控制的测试:

实验代码(sem_buff_share.c):
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
char buff[10];
int i = 0, j = 0;
sem_t * sem_place = NULL;
sem_t * sem_data = NULL;
void *work1()
{
	while(1)
    {
        sem_wait(sem_place);//消耗空间资源wait操作
        scanf("%c\n",&buff[i]);
        sem_post(sem_data);//释放data资源signal操作
        i++;
        i = i%10;
    }
	return NULL;
}
void *work2()
{
	while(1)
	{
        sem_wait(sem_data);//消耗data资源wait操作
        printf("我是输出:%c\n",buff[j]);
        sem_post(sem_place);//释放空间资源signal操作
        sleep(1);
        j++;
        j = j%10;
	}
	return NULL;
}

int main()
{
	sem_place = sem_open("placesem",O_CREAT,0666,10);//空间资源初始化为10
    sem_data = sem_open("datasem",O_CREAT,0666,0);//data资源初始化为0
	pthread_t p1, p2;
	pthread_create(&p1, NULL, work1, NULL);
	pthread_create(&p2, NULL, work2, NULL);
	pthread_join(p1, NULL);
	pthread_join(p2, NULL);
	sem_close(sem_place);
    sem_close(sem_data);
	unlink("placesem");
    unlink("datasem");
	return 0;
}

本题为操作系统中的生产者和消费者问题,需要设置关于数组空间的信号量sem_place(初始值为10),和有关数组中字符个数的信号量sem_data(初始值为0).

实验结果

我们可以看到即使输入比输出快出整个数组的字符个数也不会出现错误。
在这里插入图片描述

四、进程通信问题。阅读并运行共享内存、管道、消息队列三种机制的代码

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

首先是信号量存在的情况,程序能正常运行,receiver可以正确读出sender发送的字符串。

实验代码(sender.c)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>

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);
    }
    printf("sender共享内存地址:%d",shm_id);
    //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;
}
实验代码(receiver.c)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>

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);
    }
    printf("receiver共享内存地址:%d",shm_id);
    //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;
}
测试结果

在这里插入图片描述
接着我们去掉程序中的信号量,receiver不能正常接收到sender发送的数据:

实验代码(nosem_sender.c)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>

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;
}

实验代码(nosem_receiver.c)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>

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);
            
            sleep(5);

            /*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;
}
实验结果:

当sender不发送数据时receiver会从缓冲区继续读之前的数据,导致错误发生。
在这里插入图片描述
输出共享内存地址相同:

实验结果:

共享内存区域是被多个进程共享的一部分物理内存。多个进程都把该内存区域映射到自己的虚拟地址空间,则这些进程就都可以直接访问该共享内存区域,从而可以通过该区域进行通信。
在这里插入图片描述

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

实验代码(pipe.c)
#include <stdio.h>
#include <unistd.h>     //for pipe()
#include <string.h>     //for memset()
#include <stdlib.h>     //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;
}
实验代码(fifo_send.c)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <fcntl.h>


#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;
}
实验代码(fifo_rcv.c)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <fcntl.h>


#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;
}

实验结果:

有名管道和无名管道通信系统调用已经实现了同步机制,我们可以看出当接收方未启动时那么发送方会阻塞等待,如果发送方未启动时那么接收方会阻塞等待。
在这里插入图片描述
在这里插入图片描述

c)消息通信系统调用是否已经实现了同步机制?通过实验验证,发送者和接收者如何同步的。比如,在什么情况下,发送者会阻塞,什么情况下,接收者会阻塞?

实验代码(client.c):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <signal.h>

#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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <signal.h>

#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;
}
实验结果

正常运行:
在这里插入图片描述
服务器端未打开:
客户端进入阻塞
在这里插入图片描述
客户端未打开:
服务器端进入阻塞
在这里插入图片描述
消息通信系统调用已经实现了同步机制。

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

首先将寄存器压入栈顶:pushl %ebp,接着将进程的栈指针存储在构造的struct thread中,并且提前获取在结构体中的内存地址偏移量因为汇编中无法直接获取结构体中的栈指针,在知道结构体偏移量之后还需要获取当前进程在内存中的偏移量这样才能获取堆栈的位置,在实现进程上下文切换的函数中本身就将当前进程指针和要进行进程切换的指针作为参数那么只需要直接进行访问就行,在了解以上信息后就可以计算在整个内存中栈的地址了,这是正在运行进程的保存过程,恢复过程就是保存过程的逆操作,只要找到地址将栈中的信息pop出来就可以做到恢复。

git代码

参考文章:
https://www.cnblogs.com/Jimmy1988/p/7706980.html
https://www.cnblogs.com/Jimmy1988/p/7699351.html
https://www.cnblogs.com/Jimmy1988/p/7553069.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值