杭电操作系统实验三报告

写给看这篇博客的杭电学弟:
按理说操作系统实验应该自己做,这样能锻炼自己。鉴于我的报告还是比较有参考价值,能让以后的同学参考一下,就做成md的形式。

实验三报告

一、实验内容:

(1)实验名:Linux进程管理
(2)实验要求:
1)实现一个模拟的shell
2)实现一个管道通信程序
3)利用Linux消息队列通信机制实现两个线程间的通信
4)利用Linux共享内存通信机制实现两个进程间的通信

二、实验思路

(1)实验一

pid = fork()会返回多个值,只需在fork()后使用多个判断语句即可。
pid<0表示错误,我打印error之后退出
pid=0表示子进程运行,使用execl替换进程,替换为我们想要的进程,如cmd.o。
pid>0表示父进程运行,使用wait(NULL)函数等待所有子进程的退出。

效果见实验结果(1)
代码见附录demo1

(2)实验二

使用7个信号量:
Mutex = sem_open(“Mutex”, O_CREAT, 0666, 1);
send1 = sem_open(“send1”, O_CREAT, 0666, 1);
send2 = sem_open(“send2”, O_CREAT, 0666, 1);
send3 = sem_open(“send3”, O_CREAT, 0666, 1);
receive1 = sem_open(“receive1”, O_CREAT, 0666, 0);
receive2 = sem_open(“receive2”, O_CREAT, 0666, 0);
receive3 = sem_open(“receive3”, O_CREAT, 0666, 0);

1)
建立无名管道:
int fd[2];
int ret = pipe(fd);//无名管道

2)先fork三个子进程,编写各自的操作

每个子进程等待各自的send信号量,再等待Mutex信号量,进行,完成后释放各自的receiver:
P(send)
P(Mutex)
。。。发送内容到管道。。。
V(receiver)
V(Mutex)

父进程等待三个receiver信号量,接收管道内容后,释放三个send信号量:
P(receiver1)
P(receiver2)
P(receiver3)
P(Mutex)
。。。发送内容到管道。。。
V(receiver1)
V(receiver2)
V(receiver3)
V(Mutex)

效果见实验结果(2)
代码见附录demo2

(3)实验三

四个信号量:
sem_send = sem_open(“send”, O_CREAT, 0666, 1);
sem_receive = sem_open(“receive”, O_CREAT, 0666, 0);
sem_over1 = sem_open(“over1”, O_CREAT, 0666, 0);
sem_over2 = sem_open(“over2”, O_CREAT, 0666, 0);

发送:(以sender1为例)
While(1)
{
P(send)
发送消息给接收消息队列
if(发送的是”exit”)
Break;
P(receive)
}
P(over1)
发送退出消息
V(send)
退出
接收:
Int flag1 = 0;
Int flag2 = 0;
While(1)
{
P(receive)
发送消息给接收消息队列
if(接收到的是1发来的”exit”)
Flag1 = 1
V(over1)
if(接收到的是2发来的”exit”)
Falg2 = 1
V(over2)
P(send)

If(flag1 && flag2)
Break;
}
退出

代码见附录demo3

(4)实验四

1)
共享内存中放的是字符串
支持不断地发送,不断地接收(加接收延时即可)
在发送消息中,第一位表示是哪个发送者发送的,以此区分发送者。

2)
sem_send = sem_open(“send”, O_CREAT, 0666, 2);
sem_receive = sem_open(“receive”, O_CREAT, 0666, 0);
sem_over1 = sem_open(“over1”, O_CREAT, 0666, 0);
sem_over2 = sem_open(“over2”, O_CREAT, 0666, 0);

发送:
While(1)
P(send)
发送信息
V(receive)
P(over1)
显示传回信息
V(send)

接收:
Int flag1 = 0;
Int flag2 = 0;
While(1)
P(receive)
If(是sender1发送的)
If(发送的是“exit”)
Flag1 = 1
V(over1)
If(是sender2发送的)
If(发送的是“exit”)
Falg2 = 1
V(over2)

三、实验结果与遇到的问题

(1)实验一

遇到的问题及解决:一开始父进程没有等待子进程结束导致出错

(2)实验二
经测试,可以做到不同顺序!.

遇到的问题及解决:一开始连续三个fork(),其实创建了孙子进程,并不是三个并列的子进程,正确写法是:
pid1 = fork();
if(pid1 > 0)
{
pid2 = fork();
if(pid2 > 0)
{
pid3 = fork();
}
}
遇到的问题及解决:接收的数据乱码。原因是当初放数据时,没有考虑‘\0’的存在,应该合理设计,只在最后加‘\0’。

(3)实验三

支持多终端发送,单终端接收。
发送顺序不是固定。

遇到的问题及解决:无法申请到消息队列,试过各种方法,都是返回-1。重启就行了,估计是调试太多次,把能用的消息队列都搞没了。

(4)实验四

支持多终端发送,单终端接收。
发送顺序不是固定。
四、实验总结
这个实验我是最早验收成功的。一开始,投机求巧,只完成第四个小实验的多终端,而第三个小实验依旧使用单终端多线程(参考网上的),刚好贾老师出差就找赵伟华老师验收,是想让自己碰碰运气,结果运气不好只演示第三个,结果分数有点低。一开始的心态的确和大多数人一样,觉得水水过就好了,后来看到室友都实现了第三个实验的多终端,我也不甘示弱,还是把第三个小实验重写了一下。

六、附录

1)Demo1
#include 
#include 
#include 
#include 

int main()
{
    char input[20];
    pid_t pid;

//    printf("输入要运行的程序名$\n");
//    scanf("%s", input);
    while(1)
    {
        printf("输入要运行的程序名$\n");
        scanf("%s", input);

        if(strcmp(input,"exit") == 0)
        {
            printf("父进程退出\n");
            printf("\n进程结束,pid:%d\n", getpid());
            exit(0);
        }
        else if(strcmp(input,"cmd3") == 0 || strcmp(input,"cmd2") == 0 || strcmp(input,"cmd1") == 0)
        {
            //创建子进程
            pid = fork();

            if(pid < 0)
            {
                printf("vfork() error\n");
                exit(-1);
            }
            else if(pid == 0)
            {
                printf("i am the child process, my process id is %d\n",getpid());
                char path[80] = "../t1/";
                char *lastName = ".o";
                strcat(path, input);
                strcat(path, lastName);

                execl(path,"",NULL);
            }
            else
            {
                printf("i am the parent process, my process id is %d\n",getpid());

                pid_t temp = wait(NULL);
                printf("\n进程结束,pid:%d\n", temp);
            }
        }
        else
        {
            printf("Command not found\n");
//            printf("输入要运行的程序名$\n");
//            scanf("%s", input);
            continue;
        }

    }

    return 0;
}

(2)Demo2

#include 
#include 
#include 

#include 
#include //信号量头文件
#include 

#define MAX_PIPE_CAPACIPY 100


int main()
{
    int fd[2];
    sem_t *Mutex;
    sem_t *send1, *send2, *send3;
    sem_t *receive1, *receive2, *receive3;

    sem_unlink("Mutex");
    sem_unlink("send1");
    sem_unlink("send2");
    sem_unlink("send3");
    sem_unlink("receive1");
    sem_unlink("receive2");
    sem_unlink("receive3");

    Mutex = sem_open("Mutex", O_CREAT, 0666, 1);
    send1 = sem_open("send1", O_CREAT, 0666, 1);
    send2 = sem_open("send2", O_CREAT, 0666, 1);
    send3 = sem_open("send3", O_CREAT, 0666, 1);
    receive1 = sem_open("receive1", O_CREAT, 0666, 0);
    receive2 = sem_open("receive2", O_CREAT, 0666, 0);
    receive3 = sem_open("receive3", O_CREAT, 0666, 0);

    int ret = pipe(fd);//无名管道
    if (ret == -1)
    {
        printf("pipe create error\n");
        exit(-1);
    }


    pid_t pid1;
    pid_t pid2;
    pid_t pid3;
//    pid1 = fork();
//    pid2 = fork();
//    pid3 = fork();

    pid1 = fork();
    if(pid1 > 0)
    {
        pid2 = fork();
        if(pid2 > 0)
        {
            pid3 = fork();
        }
    }

    if(pid1 < 0 || pid2 < 0 || pid3 < 0)
    {
        sem_unlink(Mutex);
        sem_unlink(send1);
        sem_unlink(send2);
        sem_unlink(send3);
        sem_unlink(receive1);
        sem_unlink(receive2);
        sem_unlink(receive3);
        exit(0);
    }
    if(pid1 == 0)
    {
        close(fd[0]);
        sem_wait(send1);
        sem_wait(Mutex);

        char buf[3];
        memset(buf, '1', 3);
        write(fd[1], buf, sizeof(buf));
        printf("pid:%d 进程1放入数据:%s\n",getpid(),"111");


        sleep(1);

        sem_post(receive1);
        sem_post(Mutex);

//        exit(0);
    }
    if(pid2 == 0)
    {
        close(fd[0]);
        sem_wait(send2);
        sem_wait(Mutex);

        char buf[3];
        memset(buf, '2', 3);
        write(fd[1], buf, sizeof(buf));
        printf("pid:%d 进程2放入数据:%s\n",getpid(),"222");

        sleep(1);

        sem_post(receive2);
        sem_post(Mutex);
    }
    if(pid3 == 0)
    {
        close(fd[0]);
        sem_wait(send3);
        sem_wait(Mutex);

        char buf[3]="33";
        write(fd[1], buf, sizeof(buf));
        printf("pid:%d 进程3放入数据:%s\n",getpid(),buf);

        sleep(1);

        sem_post(receive3);
        sem_post(Mutex);

    }
    else
    {
        close(fd[1]);


        sem_wait(receive1);
        sem_wait(receive2);
        sem_wait(receive3);
        sem_wait(Mutex);

        char str[1024];

        read(fd[0], str, 1024);

        printf("pid:%d 父进程接收数据:%s\n", getpid(), str);

        sleep(1);

        sem_post(send1);
        sem_post(send2);
        sem_post(send3);
        sem_post(Mutex);


        exit(0);
    }

    return 0;
}

(3)Demo3

//线程间的通信s_r.h
//IPC消息队列
#include 
#include 
#include 

#include 
#include 
#include 
#include 

#include 
#include //信号量头文件

sem_t *sem_send;
sem_t *sem_receive;
sem_t *sem_over1;
sem_t *sem_over2;

//缓冲区mymsg
struct my_msgbuf
{
    long mtype;//消息类型1为发送者的消息,2为接收的消息。
    int sendid;//1为发送者1,2为发送者2。
    char mtext[100];
};

void init_signal()
{
    //初始化信号量
    sem_send = sem_open("send", O_CREAT, 0666, 1);
    sem_receive = sem_open("receive", O_CREAT, 0666, 0);
    sem_over1 = sem_open("over1", O_CREAT, 0666, 0);
    sem_over2 = sem_open("over2", O_CREAT, 0666, 0);


}
//sender1.c
#include "s_r.h"

int main()
{
    int msgid;//消息队列标识符

    scanf("%d", &msgid);
    printf("%d\n", msgid);

    init_signal();

    char str[100];
    struct my_msgbuf s_msg;//消息发送区
    s_msg.mtype = 1;
    s_msg.sendid=1;

    //不断发送
    while(1)
    {
        memset(str, '\0', strlen(str));
        printf("\ntid:%u 线程1发送: ", (unsigned int)pthread_self());
        scanf("%s", str);

        sem_wait(sem_send);

        if(strcmp(str, "exit") == 0)
        {
            strcpy(s_msg.mtext, "end1");
            msgsnd(msgid, &s_msg, sizeof(struct my_msgbuf), 0);
            sem_post(sem_receive);
            break;
        }

        strcpy(s_msg.mtext, str);
        printf("%s", s_msg.mtext);
        msgsnd(msgid, &s_msg, sizeof(struct my_msgbuf), 0);

        sem_post(sem_receive);
    }
    sem_wait(sem_over1);

    struct my_msgbuf r_msg;
    msgrcv(msgid, &r_msg, sizeof(struct my_msgbuf), 0, 0);
    printf("****线程1收到线程%d的: %20s\n", r_msg.sendid, r_msg.mtext);

    sem_post(sem_send);
    return 0;
//    pthread_exit(NULL);//线程终止
}
//sender2.c
#include "s_r.h"

int main()
{
    int msgid;//消息队列标识符

    scanf("%d", &msgid);
    printf("%d\n", msgid);

    init_signal();

    char str[100];
    struct my_msgbuf s_msg;//消息发送区
    s_msg.mtype = 1;
    s_msg.sendid= 2;


    //不断发送
    while(1)
    {
        printf("\ntid:%u 线程2发送: ", (unsigned int)pthread_self());
        scanf("%s", str);

        sem_wait(sem_send);

        if(strcmp(str, "exit") == 0)
        {
            strcpy(s_msg.mtext, "end2");
            msgsnd(msgid, &s_msg, sizeof(struct my_msgbuf), 0);
            sem_post(sem_receive);
            break;
        }

        strcpy(s_msg.mtext, str);
        msgsnd(msgid, &s_msg, sizeof(struct my_msgbuf), 0);

        sem_post(sem_receive);
    }

    sem_wait(sem_over2);
    struct my_msgbuf r_msg;
    msgrcv(msgid, &r_msg, sizeof(struct my_msgbuf), 0, 0);
    printf("****线程2收到线程%d的: %20s\n", r_msg.sendid, r_msg.mtext);

    sem_post(sem_send);

    return 0;
//    pthread_exit(NULL);//线程终止
}
//receiver.c
#include "s_r.h"


int main()
{
    int msgid;//消息队列标识符
    msgid = msgget(IPC_PRIVATE, 0666|IPC_CREAT);

    printf("%d\n", msgid);

    sem_unlink("send");
    sem_unlink("receive");
    sem_unlink("over1");
    sem_unlink("over2");

    init_signal();

    struct my_msgbuf r_msg;//消息接受区
    struct my_msgbuf s_msg;
    s_msg.mtype = 2;
    s_msg.sendid = 3;
    int flag_over1 = 0;
    int flag_over2 = 0;

    while (1)
    {
        sem_wait(sem_receive);

        msgrcv(msgid, &r_msg, sizeof(struct my_msgbuf), 0, 0);
        printf("********线程3收到线程%d的: %20s\n", r_msg.sendid, r_msg.mtext);


        if (r_msg.sendid == 1)
        {
            if (strcmp(r_msg.mtext, "end1") == 0)
            {
                printf("发送over1\n");
                strcpy(s_msg.mtext, "over1");
                msgsnd(msgid, &s_msg, strlen(s_msg.mtext), 0);

                sem_post(sem_over1);
                flag_over1 = 1;
            }
            else
            {
                sem_post(sem_send);
            }
        }
        else if(r_msg.sendid == 2)
        {
            if (strcmp(r_msg.mtext, "end2") == 0)
            {
                printf("发送over2\n");
                strcpy(s_msg.mtext, "over2");
                msgsnd(msgid, &s_msg, sizeof(struct my_msgbuf), 0);

                sem_post(sem_over2);
                flag_over2 = 1;
            }
            else
            {
                sem_post(sem_send);
            }
        }

        if (flag_over1 && flag_over2)
            break;
    }


    sem_unlink("send");
    sem_unlink("receive");
    sem_unlink("over1");
    sem_unlink("over2");

    return 0;
}
Makefile:
all: sender1 sender2 receiver
sender1: sender1.c
	gcc sender1.c -pthread -o sender1
sender2: sender2.c
	gcc sender2.c -pthread -o sender2
receiver: receiver.c
	gcc receiver.c -pthread -o receiver

(4)Demo4

//sender1创建共享内存
#include "../t4/s_r.h"

int main()
{
    //初始化信号量
    sem_unlink("send");
    sem_unlink("receive");
    sem_unlink("over1");
    sem_unlink("over2");

    init_signal();
//    printf("shmid: %d, shmp");

    //初始化共享内存
    memset((char *)shmp, '\0', MEM_MIN_SIZE);

    char s_str[100];
    char temp[MEM_MIN_SIZE];
    while(1)
    {
        printf("输入你要发送的信息:\n");
        scanf("%s", s_str);

        sem_wait(sem_send);

        //输入到共享内存中
        memset((char *)shmp, '\0', MEM_MIN_SIZE);
        strcpy(temp, (char *)shmp);
        char t[2] = "1";
        strcat(temp, t);
        strcat(temp, s_str);
        strcpy((char *)shmp, temp);

        sem_post(sem_receive);
        sem_wait(sem_over1);

        char r_str[100];
        strcpy(r_str, (char *)shmp);
        printf("接收到: %s\n", r_str);


        if(strcmp(r_str, "over1") == 0)
        {
            break;
        }
        sem_post(sem_send);

    }

    printf("退出sender1!!\n");
    shmdt(shmp);

    exit(0);
}
//sender2创建共享内存
#include "../t4/s_r.h"

int main()
{
    init_signal();
//    printf("shmid: %d, shmp");

    //初始化共享内存
    memset((char *)shmp, '\0', MEM_MIN_SIZE);

    char s_str[100];
    char temp[MEM_MIN_SIZE];
    while(1)
    {
        printf("输入你要发送的信息:\n");
        scanf("%s", s_str);

        sem_wait(sem_send);

        //输入到共享内存中
        memset((char *)shmp, '\0', MEM_MIN_SIZE);
        strcpy(temp, (char *)shmp);
        char t[2] = "2";
        strcat(temp, t);
        strcat(temp, s_str);
        strcpy((char *)shmp, temp);

        sem_post(sem_receive);
        sem_wait(sem_over2);

        char r_str[100];
        strcpy(r_str, (char *)shmp);
        printf("接收到: %s\n", r_str);


        if(strcmp(r_str, "over2") == 0)
        {
            break;
        }
        sem_post(sem_send);

    }

    printf("退出sender2!!\n");
    shmdt(shmp);

    exit(0);
}
//receiver
#include "../t4/s_r.h"

int main()
{
    init_signal();

    int flag_end1 = 0;
    int flag_end2 = 0;

    char r_str[100];
    char temp[MEM_MIN_SIZE];

    while(1)
    {
        sem_wait(sem_receive);

        char recv[100];
        strcpy(recv, (char *)shmp);

        strncpy(r_str, recv+1, strlen(recv));
        printf("从sender%c 接收到: %s\n",recv[0],r_str);

        if(recv[0] == '1')
        {
            if(strcmp(r_str, "exit") == 0)
            {
                char s_str[100]="over1";
                memset((char *)shmp, '\0', MEM_MIN_SIZE);
                strcpy(temp, (char *)shmp);
                strcat(temp, s_str);
                strcpy((char *)shmp, temp);
                flag_end1 = 1;
            }
            else
            {
                char s_str[100]="receiver success";
                memset((char *)shmp, '\0', MEM_MIN_SIZE);
                strcpy(temp, (char *)shmp);
                strcat(temp, s_str);
                strcpy((char *)shmp, temp);
            }
            sem_post(sem_over1);
        }
        if(recv[0] == '2')
        {
            if(strcmp(r_str, "exit") == 0)
            {
                char s_str[100]="over2";
                memset((char *)shmp, '\0', MEM_MIN_SIZE);
                strcpy(temp, (char *)shmp);
                strcat(temp, s_str);
                strcpy((char *)shmp, temp);
                flag_end2 = 1;
            }
            else
            {
                char s_str[100]="receiver success";
                memset((char *)shmp, '\0', MEM_MIN_SIZE);
                strcpy(temp, (char *)shmp);
                strcat(temp, s_str);
                strcpy((char *)shmp, temp);
            }
            sem_post(sem_over2);
        }


        if(flag_end1 == 1 && flag_end2 == 1)
        {
            break;
        }
    }

    sem_unlink("send");
    sem_unlink("receive");
    sem_unlink("over1");
    sem_unlink("over2");

    shmdt(shmp);
    shmctl(shmid, IPC_RMID, NULL);

    printf("接收端退出!!\n");
    exit(0);
}
//s_r.h
#include 
#include 
#include 

#include 
#include 

#include //信号量头文件
#include 

#define MEM_MIN_SIZE 1024
#define KEY 1111

sem_t *sem_send;
sem_t *sem_receive;
sem_t *sem_over1;
sem_t *sem_over2;

key_t key;
int shmid;
void *shmp;

void init_signal()
{
    //初始化信号量
    sem_send = sem_open("send", O_CREAT, 0666, 2);
    sem_receive = sem_open("receive", O_CREAT, 0666, 0);
    sem_over1 = sem_open("over1", O_CREAT, 0666, 0);
    sem_over2 = sem_open("over2", O_CREAT, 0666, 0);

    shmid = shmget(KEY, MEM_MIN_SIZE, 0666|IPC_CREAT); //创建共享内存,key = 0(IPC_PRIVATE) 创建一个新对象。成功则返回id (一个与key相关的标识符)
    if(shmid < 0)
    {
        printf("创建共享内存出错!\n");
        exit(-1);
    }

    shmp = shmat(shmid, NULL, 0);//指定共享内存映射到新虚拟地址空间,返回起始地址
    if((int)shmp == -1)
    {
        printf("映射内存出错!\n");
        exit(-1);
    }
}
Makefile:
all: sender1 sender2 receiver
sender1: sender1.c
	gcc sender1.c -pthread -o sender1
sender2: sender2.c
	gcc sender2.c -pthread -o sender2
receiver: receiver.c
	gcc receiver.c -pthread -o receiver

你可能感兴趣的:(其他未分类)