精华内容
下载资源
问答
  • 实验六Linux 进程间通信2 4 课时 实验目的 理解进程通信原理掌握进程中信号量共享内存消息队列相关的函数的使用 实验原理 Linux 下进程通信相关函数除上次实验所用的几个还有 信号量 信号量又称为信号灯它是用来协调...
  • 实验六Linux进程间通信24课时 实验目的 理解进程通信原理掌握进程中信号量共享内存消息队列相关的函数的使用 实验原理 Linux下进程通信相关函数除上次实验所用的几个还有 信号量 信号量又称为信号灯它是用来协调不同...
  • 这个文档是基于有名管道进程间通信的一些实验,可以从本质上理解进程间通信的有名管道的机理。并附有源码,可以自己复制下来,进行调试。
  • 实验报告详细描述了进程间通信的实现原理,使用管道以及信号实现进出那个间通信,附有源代码实现。
  • 苏州大学操作系统原理实验。 实验报告第二个实验。 使用内存共享的方式进行进程间通信,真正的实现通信,而非单个进程的伪通信。 使用MFC的窗口模式实现的。
  • system V 进程间通信 实验报告 姓名: _______罗海员_________ 学号: ____201458506232_______ 班级: ________146-2__________ 实验报告提交时间 _______________ 验收时间 _______________ 评语: − −

    实验名称: Linux高级开发

    system V 进程间通信

    实验报告

     

    目录

    一.原创性声明..................................................................................................... 1

    二.实验要求及完成情况................................................................................ 4

    实验要求....................................................................................................... 5

    完成情况....................................................................................................... 6

    三.程序实现原理及流程图

    程序实现原理............................................................................................... 5

    流程图........................................................................................................... 6

    四.运行结果  

    消息队列....................................................................................................... 5

    Semop()函数测试..................................................................................... 6

    五.源码……………………………………………………………………………….….…………….6

     

     

     

     

    一、 原创性声明

    1.实验一和实验二代码全部原创

      实验室三部分代码来自于百度参考

    //这里表明叉子是一个临界资源

    #define DELAY (rand() % 5 + 1)

    //相当于P操作

    void

    wait_for_2fork(int no,int semid)

    {

        //哲学家左边的刀叉号数

        int left = no;

        //右边的刀叉

        int right = (no + 1) % 5;

     

        //刀叉值是两个

        //注意第一个参数是编号

        struct sembuf buf[2] = {

            {left,-1,0},

            {right,-1,0}

        };

        //信号集中有5个信号量,只是对其中的

        //资源sembuf进行操作

        semop(semid,buf,2);

    }

     

    //相当于V操作

    void

    free_2fork(int no,int semid)

    {

        int left = no;

        int right = (no + 1) % 5;

        struct sembuf buf[2] = {

            {left,1,0},

            {right,1,0}

        };

        semop(semid,buf,2);

    }

     

     

    2.参考自百度百科:

    在操作系统中,P、V操作是进程管理中的难点。这是1968年荷兰人Dijkstra给出的一种解决并发进程间互斥和同步关系的通用方法。

    1.P、V操作的意义

    定义了信号量及其上的P操作和V操作,来实现并发进程间的同步和互斥,甚至可以用来管理资源的分配。P、V操作因交换的信息量少,属于进程的低级通信。

    2. 什么是信号量?

    信号量(semaphore)是由一个值和一个指针构成的数据结构。值为整型变量,表示信息量的值;指针指向进程控制块(PCB)队列的队头,表示等待该信号量的下一个进程。如下图所示:

     

    信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。注意,信号量的初值不能为负,且其值只能由P、V操作来改变。

    3.P、V操作的含义

    P、V操作由P操作原语和V操作原语组成(原语是不可中断的过程),对信号量S进行操作,具体定义如下:

    P(S):

    ① 将信号量S的值减1,即S=S-1;

    ② 如果S≥0,则该进程继续执行;否则该进程状态置为阻塞状态,进程PCB排入信号量PCB队列末尾,放弃CPU,等待V操作的执行。

    V(S):

    ① 将信号量S的值加1,即S=S+1;

    ② 如果S≤0,释放信号量队列中第一个PCB所对应的进程,将进程状态由阻塞态改为就绪态。执行V操作的进程继续执行。

    一般来说,信号量S≥0时,S表示可用资源的数量。执行一次P操作意味着请求分配一个单位资源,因此S的值减1;当S<0时,表示已经没有可用资源,请求者必须等待别的进程释放该类资源,它才能运行下去。而执行一个V操作意味着释放一个单位资源,因此S的值加1;若S?0,表示有某些进程正在等待该资源,因此要唤醒一个阻塞状态的进程,使之成为就绪状态。

    4. 利用信号量和P、V操作实现进程互斥

    一般地,n个进程利用信号量和P、V操作实现进程互斥的一般模型如下:

    进程P1 进程P2 …… 进程Pn

    …… …… ……

    P(S);P(S); P(S);

    临界区; 临界区; 临界区;

    V(S);V(S); V(S);

    …… …… …… ……

    其中S是互斥信号量,初值为1。

    使用P、V操作实现进程互斥时应该注意的问题是:

    (1)每个程序中,用户实现互斥的P、V操作必须成对出现,先做P操作,进临界区,后做V操作,出临界区。若有多个分支,要认真检查P、V操作的成对性。

    (2)P、V操作应分别紧靠临界区的头尾部,临界区的代码应尽可能短,不能有死循环。

    (3)互斥信号量的初值一般为1。

    5. 利用信号量和P、V操作实现进程同步

    P、V操作是典型的进程同步机制之一。用一个信号量与一个消息联系起来,当信号量的值为0时,表示期望的消息尚未产生;当信号量的值为非0时,表示期望的消息已经存在。用P、V操作实现进程同步时,调用P操作测试消息是否到达,调用V操作来发送消息。

    使用P、V操作实现进程同步时应该注意的问题是:

    (1)分析进程间的制约关系,确定信号量种类。在保持进程间有正确的同步关系情况下,哪个进程应先执行,哪些进程后执行,彼此间通过什么信号量进行协调,从而明确要设置哪些信号量。

    (2)信号量的初值与相应资源的数量有关,也与P、V操作在程序代码中出现的位置有关。

    (3)同一信号量的P、V操作要成对出现,但它们分别在不同的进程代码中。

     

     

    二、实验要求及完成情况

    1.实验要求:

    (1)实验11-3 共享内存实现原理及程序分析

    示例程序(p288):   shm_sem_example_send.c         shm_sem_example_recv.c  

    简述共享内存实现原理。

    运行示例程序,给出运行截图,分析其执行过程。绘制程序流程图

     

    2)实验11-4 消息队列

    发送端向消息队列写入若干消息,类型随机设定。

    接收端根据用户输入的消息类型接收消息。

    (3)实验11-5 信号量

    测试信号量操作函数semop()。

    使sem_op分别取不同的值(>0, =0, <0), 跟踪semval、semncnt、semzcnt、sempid值的变化, 查看进程被阻塞和唤醒的情况,分析并得出结论。

    (4)实验11-10 哲学家就餐问题

    哲学家就餐问题描述:5个哲学家,5个筷子。5个哲学家围坐在一张桌子上,筷子放在分别放在每个哲学家的两旁。如果所有哲学家在某个时刻同时拿起左边的筷子,那么右边的筷子就都被其他的哲学家拿了,造成大家都无法吃饭。但是大家都不想放下左边的筷子(规则是先拿起左边筷子在拿起右边的,吃完饭在放下两个筷子),这就是死锁。
    解决这个问题有个办法是在拿起筷子前先判断左右两个筷子是否可用,可用才能拿,而且是同时拿,这样不相邻的哲学家就可以吃上饭,不会造成死锁。

     

    2.完成情况:

    均顺利完成了实验,首先,实现了发送端向消息队列写入若干消息,类型随机设定。接收端根据用户输入的消息类型接收消息。测试了信号量操作函数semop()。

    使sem_op分别取不同的值(>0, =0, <0), 跟踪semval、semncnt、semzcnt、sempid值的变化, 查看进程被阻塞和唤醒的情况,分析并得出结论。

    分析完成了哲学家就餐问题,解决了死锁问题!

     

    三、程序实现原理及流程图(手写)

    1.实验11-3

    (1)运行结果如下:

     

     

    (2)流程图如下:

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    2.自己编写的11-4,11-5,11-10实验原理如下:

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    四、运行结果

    1.消息队列测试

     

     

     

     

     

     

     

     

     

     

     

    2.测试信号量操作函数semop(),测试如下

     

     

     

     

     

     

     

     

     

     

     

    3.哲学家就餐问题

     

     

     

     

     

     

     

     

     

     

     

    五、源码

    【实验11-4消息队列】
    
    //send.c
    
    #include<stdio.h>
    
    #include<stdlib.h>
    
    #include<string.h>
    
    #include<unistd.h>
    
    #include<sys/types.h>
    
    #include<sys/ipc.h>
    
    #include<sys/stat.h>
    
    #include<sys/msg.h>
    
    #include<error.h>
    
     
    
    structmy_msg
    
    {
    
        long int my_msg_type;
    
        char text[BUFSIZ];
    
    }msgbuf;
    
     
    
    intmain(int argc,char *argv[])
    
    {
    
        key_t key;
    
        key=ftok(argv[1],100);
    
        int runningFlg=1;
    
        int msgid;
    
        msgid=msgget((key_t)1234,IPC_CREAT | 0666);
    
     
    
        if(msgid==-1)
    
        {
    
           perror("msgget failed!\n");
    
           exit(1);
    
        }
    
        while(runningFlg==1)
    
        {
    
           printf("please inout strings:");
    
           fgets(msgbuf.text,BUFSIZ,stdin);
    
           msgbuf.my_msg_type=1;
    
           if(msgsnd(msgid,(void*)&msgbuf,BUFSIZ,0)==-1)
    
           {
    
               perror("send messagesfailed!\n");
    
               exit(1);
    
           }
    
           if(strncmp(msgbuf.text,"end",3)==0)
    
           {
    
               runningFlg=0;
    
           }
    
        }
    
        return 0;
    
    }
    
     
     
    
    //rec.c
    
    intmain(int argc,char *argv[])
    
    {
    
        //key_t key;
    
        //key=ftok(argv[1],100);
    
     
    
        int runningFlg=1;
    
        int msgid;
    
        long int msg_to_receive=0;
    
        msgid=msgget((key_t)1234,IPC_CREAT | 0666);
    
     
    
        if(msgid==-1)
    
        {
    
           printf("msgget failed!\n");
    
           exit(1);
    
        }
    
        while(runningFlg==1)
    
        {
    
           if(msgrcv(msgid,(void*)&msgbuf,BUFSIZ,msg_to_receive,0)==-1)
    
           {
    
               perror("msgrcv failed!\n");
    
               exit(1);
    
           }
    
           printf("接收到的字符串是+%s",msgbuf.text);
    
           if(strncmp(msgbuf.text,"end",3)==0)
    
           {
    
               runningFlg=0;
    
           }
    
        }
    
        if(msgctl(msgid,IPC_RMID,0)==-1)
    
        {
    
               perror("msgct(IPC_RMID)failed!\n");
    
               exit(1);
    
        }
    
        return 0;
    
    }
    
     
    
     
    
    【实验11-5信号量】部分
    
    1.SystemV信号量的继承和销毁
    
    (1)继承
    
    和POSIX的有名信号量一样,父进程中打开的信号量在子进程中仍然是保持着打开状态的。
    
     
    
    (2)销毁
    
    对于一个持有该信号量的进程在没有释放该信号量的情况下就终止了。那么该进程所占用的信号量内核是不会进行释放的。
    
    当通过semctl传入IPC_RMID对该信号量集进行删除时,会立即将该信号量从系统中彻底删除,不能再对该信号量进行任何访问。这和POSIX信号量是不一样的。
    
    下面代码进行了测试:
    
    unionsemun
    
    {
    
        int val;                          
    
        struct semid_ds *buf;            
    
        unsigned short int *array;     
    
        struct seminfo *__buf;         
    
    };
    
     
    
    intCreateKey(const char * pathName)
    
    {
    
        int fd = open( pathName, O_CREAT , 0666);
    
     
    
        if (fd < 0)
    
        {
    
            cout<<"open fileerror..."<<strerror(errno)<<endl;
    
            return -1;
    
        }
    
        close(fd);
    
        return ftok(pathName, 0);
    
    }
    
     
    
    intmain()
    
    {
    
       int semId;
    
       semun arg;
    
     
    
       //解决信号量的创建和初始化不是原子操作的一种方案
    
       if ((semId = semget(CreateKey(SEM_PATHNAME),1, IPC_CREAT | IPC_EXCL | 0666)) >= 0)
    
       {
    
           arg.val = 4;
    
     
    
           if (semctl(semId, 0, SETVAL, arg) <0)
    
           {
    
               cout<<"semctl error"<<strerror(errno)<<endl;
    
               return -1;
    
           }
    
       }
    
       else if (errno == EEXIST)
    
       {
    
           semId = semget(CreateKey(SEM_PATHNAME),1, 0666);
    
       }
    
       else
    
       {
    
           cout<<"semget error"<<strerror(errno)<<endl;
    
           return -1;
    
       }
    
     
    
       cout<<"parent:semvalue:"<<semctl(semId, 0, GETVAL)<<endl;
    
     
    
       if (fork() == 0)
    
       {
    
           struct sembuf buffer;
    
           buffer.sem_num = 0;
    
           buffer.sem_op = -2;
    
           buffer.sem_flg = 0;
     
           semop(semId, &buffer, 1);
    
           cout<<"child:semvalue:"<<semctl(semId, 0, GETVAL)<<endl;
    
           exit(0);
    
       }
    
     
    
       sleep(1);
    
       cout<<"parent:semvalue:"<<semctl(semId, 0, GETVAL)<<endl;
    
    }
    
     
    
     
    
    2.下面代码测试信号量集的删除:
    
    intmain()
    
    {
    
       int semId;
    
       semun arg;
    
     
       //解决信号量的创建和初始化不是原子操作的一种方案
    
       if ((semId = semget(CreateKey(SEM_PATHNAME),1, IPC_CREAT | IPC_EXCL | 0666)) >= 0)
    
       {
    
           arg.val = 4;
    
           if (semctl(semId, 0, SETVAL, arg) <0)
    
           {
    
               cout<<"semctl error"<<strerror(errno)<<endl;
    
               return -1;
    
           }
    
       }
    
       else if (errno == EEXIST)
    
       {
    
           semId = semget(CreateKey(SEM_PATHNAME),1, 0666);
    
       }
    
       else
    
       {
    
           cout<<"semget error"<<strerror(errno)<<endl;
    
           return -1;
    
       }
    
       cout<<"parent:semvalue:"<<semctl(semId, 0, GETVAL)<<endl;
    
     
    
       if (fork() == 0)
    
       {
    
           semctl(semId, 0, IPC_RMID);
    
           exit(0);
    
       }
    
       sleep(1);
    
     
    
       if (semctl(semId, 0, GETVAL) == -1)
    
       {
    
           cout<<"semctlerror:"<<strerror(errno)<<endl;
    
           return -1;
    
       }
    
    }
    
     
    
    3.SystemV信号量的测试
    
    下面是测试代码,信号量集中只有一个信号量,该信号量的值被设成6,每次semop获取两个信号量才能对共享资源(这里用文件代替)进行访问;
    
     
    
    intmain()
    
    {
    
       int semId;
    
       semun arg;
    
     
    
       //解决信号量的创建和初始化不是原子操作的一种方案
    
       if ((semId = semget(CreateKey(SEM_PATHNAME),1, IPC_CREAT | IPC_EXCL | 0666)) >= 0)
    
       {
    
           arg.val = 4;
    
           if (semctl(semId, 0, SETVAL, arg) <0)
    
           {
    
               cout<<"semctl error"<<strerror(errno)<<endl;
    
               return -1;
    
           }
    
       }
    
       else if (errno == EEXIST)
    
       {
           semId = semget(CreateKey(SEM_PATHNAME),1, 0666);
       }
    
       else
    
       {
           cout<<"semget error"<<strerror(errno)<<endl;
           return -1;
       }
    
     
    
       for (int i = 0; i < 3; ++i)
    
       {
    
           if (fork() == 0)
    
           {
    
                semTest(i + 1, semId);
                sleep(1);
                exit(0);
    
           }
    
       }
    
    }
    
    【实验11-10哲学家就餐问题】
    
    #include <stdio.h>
    
    #include <stdlib.h>
    
    #include <string.h>
    
    #include <stdint.h>
    
    #include <stdbool.h>
    
    #include <errno.h>
    
     
    
    #include <unistd.h>
    
    #include <sys/types.h>
    
    #include <sys/stat.h>
    
    #include <sys/ipc.h>
    
    #include <sys/sem.h>
    
    #include <sys/wait.h>
    
     
    
    #ifdef  _SEM_SEMUN_UNDEFINED
    
    union semun
    
    {
    
        int val;
    
        struct semid_ds *buf;
    
        unsigned short *array;
    
        struct seminfo *__buf;
    
    };
    
    #endif
     
    #define ERR_EXIT(m) \
    
        do { \
    
            perror(m); \
    
            exit(EXIT_FAILURE); \
    
        } while(0)
    
        
    
    int
    
    wait_1fork(int no,int semid)
    
    {
    
        //int left = no;
    
        //int right = (no + 1) % 5;
    
        struct sembuf sb = {no,-1,0};
    
        int ret;
    
        ret = semop(semid,&sb,1);
    
        if(ret < 0) {
    
           ERR_EXIT("semop");
    
        }
    
        return ret;
    
    }
    
     
    
    int
    free_1fork(int no,int semid)
    {
    
        struct sembuf sb = {no,1,0};
        int ret;
        ret = semop(semid,&sb,1);
        if(ret < 0) {
           ERR_EXIT("semop");
        }
    
        return ret;
    }
    
     
    
    //这里表明叉子是一个临界资源
    #define DELAY (rand() % 5 + 1)
    //相当于P操作
    void
    wait_for_2fork(int no,int semid)
    {
    
        //哲学家左边的刀叉号数
        int left = no;
        //右边的刀叉
    
        int right = (no + 1) % 5;
    
        //刀叉值是两个
        //注意第一个参数是编号
        struct sembuf buf[2] = {
    
            {left,-1,0},
    
            {right,-1,0}
    
        };
    
        //信号集中有5个信号量,只是对其中的
    
        //资源sembuf进行操作
    
        semop(semid,buf,2);
    
    }
    
     
    
    //相当于V操作
    
    void
    
    free_2fork(int no,int semid)
    
    {
    
        int left = no;
    
        int right = (no + 1) % 5;
    
        struct sembuf buf[2] = {
    
            {left,1,0},
    
            {right,1,0}
    
        };
    
        semop(semid,buf,2);
    
    }
     
    
    void philosophere(int no,int semid)
    {
        srand(getpid());
        for(;;) {
        #if 1
    
            //这里采取的措施是当两把刀叉都可用的时候
            //哲学家才能吃饭,这样不相邻的哲学家就可
            //吃上饭
    
            printf("%d isthinking\n",no);
            sleep(DELAY);
            printf("%d ishungry\n",no);
            wait_for_2fork(no,semid);//拿到叉子才能吃饭
            printf("%d iseating\n",no);
            sleep(DELAY);
            free_2fork(no,semid);//释放叉子
        #else
    
            //这段代码可能会造成死锁
            int left = no;
            int right = (no + 1) % 5;
            printf("%d isthinking\n",no);
            sleep(DELAY);
            printf("%d ishungry\n",no);
            wait_1fork(left,semid);
            sleep(DELAY);
            wait_1fork(right,semid);
            printf("%d iseating\n",no);
            sleep(DELAY);
            free_2fork(no,semid);
        #endif
        }
    }
    
     
    
    int
    
    main(int argc,char *argv[])
    {
    
        int semid;
        //创建信号量
        semid =semget(IPC_PRIVATE,5,IPC_CREAT | 0666);
        if(semid < 0) {
            ERR_EXIT("semid");
        }
    
        union semun su;
        su.val = 1;
        int i;
        for(i = 0;i < 5;++i) {
            //注意第二个参数也是索引
            semctl(semid,i,SETVAL,su);
    
        }
    
        //创建4个子进程
        int num = 0;
        pid_t pid;
        for(i = 1;i < 5;++i) {
            pid = fork();
            if(pid < 0) {
    
               ERR_EXIT("fork");
            }
    
            if(0 == pid) {
                num = i;
                break;
            }
        }
        //这里就是哲学家要做的事情
        philosophere(num,semid);
        return 0;
    }

     

     

     

    展开全文
  • 这是一份关于进程间通信实验报告的源代码文件
  • 进程通信实验报告

    2012-06-12 20:01:09
    LINUX进程通信实验 君若为我痴情,吾愿为君死身。
  • 实验六:进程间通信实验目的:学会进程间通信方式:无名管道,有名管道,信号,消息队列,实验要求:在父进程中创建一无名管道,并创建子进程来读该管道,父进程来写该管道在进程中为 SIGBUS注册处理函数,并向该...

    实验六:进程间通信

    实验目的:

    学会进程间通信方式:无名管道,有名管道,信号,消息队列,

    实验要求:

    在父进程中创建一无名管道,并创建子进程来读该管道,父进程来写该管道

    在进程中为 SIGBUS注册处理函数,并向该进程发送SIGBUS信号

    创建一消息队列,实现向队列中存放数据和读取数据

    实验器材:

    软件:安装了 Linux的vmware虚拟机

    硬件:PC机一台

    实验步骤:

    (一)无名管道的使用

    1编写实验代码 pipe rw.c

    #in elude

    #in elude

    #in elude

    #i nclude

    #in elude

    #i nclude

    int mai n()

    {

    int pipe_fd[2];〃管道返回读写文件描述符

    pid_t pid;

    char buf_r[100];

    char* p_wbuf;

    int r_num;

    memset(buf_r,0,sizeof(buf_r));〃 将 buf_r 初始化

    char str1[]= "parent writel holle ” ”

    char str2[]= "parent write2 pipe”n”

    r_num=30;

    /*创建管道*/

    if(pipe(pipe_fd)<0)

    {

    prin tf("pipe create error'n ”);

    return -1;

    }

    /*创建子进程*/

    if((pid=fork())==0)〃子进程执行代码

    {

    〃1、子进程先关闭了管道的写端

    close(pipe_fd[1]);

    〃2、让父进程先运行,这样父进程先写子进程才有内容读

    sleep(2);

    〃3、读取管道的读端,并输出数据

    if(read(pipe_fd[O],buf_r, r_num)<0)

    {

    printf( read error!");

    exit(-1);

    }

    printf( %s\n",buf_r);

    〃4、关闭管道的读端,并退出

    close(pipe_fd[1]);

    }

    else if(pid>0) //父进程执行代码

    {

    〃1、父进程先关闭了管道的读端

    close(pipe_fd[0]);

    〃2、向管道写入字符串数据

    p_wbuf= &str1;

    write(pipe_fd[1],p_wbuf,sizof(p_wbuf));

    p_wbuf= &str2; write(pipe_fd[1],p_wbuf,sizof(p_wbuf));

    〃3、关闭写端,并等待子进程结束后退出

    close(pipe_fd[1]);

    }

    return 0;

    }

    /***********************

    #in clude

    #in clude

    #in clude

    #i nclude

    #in clude

    #i nclude

    int mai n()

    {

    int pipe_fd[2];//管道返回读写文件描述符

    pid_t pid;

    char buf_r[100];

    char* p_wbuf;

    int r num;

    memset(buf_r,0,sizeof(buf_r));〃 将 buf_r 初始化

    char str1[]="holle";

    char str2[]="pipe";

    r_num=10;

    /*创建管道*/

    if(pipe(pipe_fd)<0)

    {

    prin tf("pipe create error'n ”); return -1;

    }

    /*创建子进程*/

    if((pid=fork())==0)〃子进程执行代码

    {

    close(pipe_fd[1]);//1、子进程先关闭了管道的写端

    〃2、让父进程先运行,这样父进程先写子进程才有内容读

    〃3、读取管道的读端,并输出数据

    if(read(pipe_fd[0],buf_r, r_n um)<0)

    {

    prin tf("read1 error!");

    exit(-1);

    }

    prin tf("\npare nt write1 %s!",buf_r);

    sleep(1);

    if(read(pipe_fd[0],buf_r, r_n um)<0)

    {

    prin tf("read2 error!");

    exit(-1);

    }

    prin tf("\npare nt write2 %s!",buf_r);

    close(pipe_fd[1]);//4、关闭管道的读端,并退出

    exit(1);

    //prin tf("child error!");

    展开全文
  • 操作系统实验报告(LINUX进程间通信)

    热门讨论 2008-12-30 21:32:51
    操作系统实验报告(LINUX进程间通信)
  • 编写一段程序,实现进程的管道通信。 使用系统调用pipe( )建立一条管道,创建两个子进程P1和P2。让P1和P2分别向管道各写一句话: child process P1 is sending messages! child process P2 is sending messages! 父...
  • 《实验二进程通信 Linux实验报告》由会员分享,可在线阅读,更多相关《实验二进程通信 Linux实验报告(9页珍藏版)》请在人人文库网上搜索。1、实验报告学号_____ 姓名____ ___ 成绩 实验二 进程通信 【实验目的和要求...

    《实验二进程通信 Linux实验报告》由会员分享,可在线阅读,更多相关《实验二进程通信 Linux实验报告(9页珍藏版)》请在人人文库网上搜索。

    1、实验报告学号_____ 姓名____ ___ 成绩 实验二 进程通信 【实验目的和要求】1、了解进程通信的概念及方法;2、了解信号量、管道;3、掌握信号量、管道和命名管道编程方法。【实验内容】1、利用命名管道实现单机QQ聊天;2、撰写实验报告;【实验原理】1、信号量(semaphore)是为那些访问相同资源的进程以及同一进程不同线程之间提供的一个同步机制。它不是用于传输数据,而只是简单地协调对共享资源的访问。信号量包含一个计数器,表示某个资源正在被访问和访问的次数,用来控制多进程对共享数据的访问。一旦成功拥有了一个信号量,对它所能做的操作只有两种:请求和释放。当执行释放操作时,系统将该信号值减。

    2、1(如果小于零,则设置为零);当执行请求操作时,系统将该信号值加1,如果加1后的值大于设定的最大值,那么系统将会挂起处理进程,直到信号值小于最大值为止。Tuxedo用信号量来确保在某一时刻只有一个进程对某一块共享内存进程访问。信号量配置太低会导致Tuxedo系统应用程序无法启动。2、管道分为两种:管道和命名管道。管道是UNIX系统IPC的最古老形式,并且所有的UNIX系统都提供这种通信机制。可以在有亲缘关系(父子进程或者是兄弟进程之间)进行通信,管道的数据只能单向流动,如果想双向流动,必须创建两个管道。管道应用的一个重大缺陷就是没有名字,因此只能用于亲缘进程之间的通信。后来以管道为基础提出命名。

    3、管道(named pipe,FIFO)的概念,该限制得到了克服。FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。值得注意的是,FIFO严格遵循先进先出(first in first out)规则,对管道及FIFO的读总是从开始处返回数据,对它们的写则是把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。【程序代码】1、lucy.c#include#。

    4、include#include#include#include#include#include#includechar write_fifo_name=ltop_fifo;char read_fifo_name=ptol_fifo;char writer=Lucy;char reader=Peter;int main(int argc,char *argv)int write_fd,read_fd;mkfifo(write_fifo_name,S_IRUSR|S_IWUSR);mkfifo(read_fifo_name,S_IRUSR|S_IWUSR);printf(hello,I am lu。

    5、cy!n);write_fd=open(write_fifo_name,O_WRONLY);if(write_fd#include#include#include#include#include#include#includechar write_fifo_name=ptol_fifo;char read_fifo_name=ltop_fifo;char writer=Peter;char reader=Lucy;int main(int argc,char *argv)int write_fd,read_fd;mkfifo(write_fifo_name,S_IRUSR|S_IWUSR);m。

    6、kfifo(read_fifo_name,S_IRUSR|S_IWUSR);printf(hello,I am peter!n);read_fd=open(read_fifo_name,O_RDONLY);if(read_fd#include 函数原型int mkfifo(const char * pathname, mode_t mode)函数传入值Pathname:要创建的的管道Mode:设置管道权限函数返回值若成功则为0,若出错返回-1FIFO相关出错信息:EACCES(无存取权限)EEXIST(指定文件不存在)ENAMETOOLONG(路径名太长)ENOENT(包含的目录不存在)ENO。

    7、SPC(文件系统余空间不足)ENOTDIR(文件路径无效)EROFS(指定的文件存在于只读文件系统中)3、信号发送和捕捉信号发送:kill()和raise()kill()函数同读者熟知的kill系统命令一样,可以发送信号给进程或进程组,它不仅可以中止进程(实际上发出SIGKILL信号),也可以向进程发送其他信号。kill()函数语法:头文件#include #include 函数原型int kill(pid_t pid,int sig)函数传入值Pid:正数:要发送信号的进程号0:信号被发送到所有的当前进程在同一进程组的进程-1:信号发给所有的进程表中的进程-1:信号发给进程组号为-pid的每一个进程Sig:信号函数返回值若成功则为0,若出错返回-1。4、fflush(stdout)目的是清空缓冲,强制结果马上显示到屏幕上。

    展开全文
  • Linux进程间通信实验十二)

    千次阅读 2019-06-02 15:04:16
    所以负责写的进程要关闭fd[0](close(fd[0])),负责读的进程要关闭fd[1](close(fd[1])) 3.重定向函数dup2():函数声明为:int dup2(int oldfd,int newfd),其功能是将参数oldfd的文件描述符传递给newfd,若函数...

    一、管道
    1.管道的逻辑结构如下:
    在这里插入图片描述
    2.在匿名管道中,写端对应的文件描述符为fd[1],读端的文件描述符为fd[0].所以负责写的进程要关闭fd[0](close(fd[0])),负责读的进程要关闭fd[1](close(fd[1]))

    3.重定向函数dup2():函数声明为:int dup2(int oldfd,int newfd),其功能是将参数oldfd的文件描述符传递给newfd,若函数调用成功则返回newfd,否则返回-1并设置errno.

    4.为了严谨起见,应使用close()函数关闭除通信端口之外的端口

    5.若所有指向管道写端的文件描述符都被关闭后仍有进程从管道的读端读取数据,那么管道中所有剩余数据都被读取后,再次read会返回0.

    6.管道中的数据以字节流的形式传输,这要求管道两端的进程事先约好数据的格式。

    7.管道是一种最基本的进程间通信机制,其实质是由内核管理的一个缓冲区。Linux将管道视为一种文件。

    8.管道通信的一般流程是:在一个进程中创建管道,通过fork()创建子进程,关闭管道多余端口,使父子进程与管道形成单向通道,进行数据传输。用popen()和pclose()两个函数即可完成管道通信的流程。

    9.popen()函数
    1)工作内容:调用pipe()创建管道,调用fork()函数创建子进程,随后在子进程中通过execve函数调用Shell命令执行相应功能。若整个流程都成功执行,则返回一个I/O文件指针;若执行失败,该函数会返回NULL。
    2)声明及解析:FILE * popen(const char * command,const char * type)。command传入要执行的Shell命令;type指定命令类型(输入w/输出r)。若type设定为r,文件指针连接到command的标准输出,返回的文件指针是可读的;若type设定为w,文件指针连接到command的标准输入,返回的文件指针是可读的。
    3)父进程与由popen创建出的进程之间的关系如图:
    在这里插入图片描述
    10.pclose函数的功能是关闭由popen打开的I/O流,并通过wait()函数等待子进程命令执行结束,返回Shell的终止状态,防止产生僵尸进程。调用popen后务必要使用pclose函数关闭打开的文件I/O指针,若pclose调用失败,则返回-1.

    11.命名管道又称FIFO,它与匿名管道不同之处在于命名管道与系统中的一个路径名关联,以文件的形式存在于文件系统中。

    12.创建FIFO文件:
    1)使用命令创建FIFO示例:mkfifo -m 644 myfifo,这个命令创建了一个名为myfifo的FIFO文件,并将其权限设置为644
    2)在程序中创建FIFO:

    int mkfifo(const char * pathname,mode_t mode)    
    

    参数1是路径名,参数2是权限

    13.命名管道作为文件,它和普通文件的不同之处在于严格遵循先进先出原则。而且它和匿名管道一样,当缓冲区为空或缓冲区满时会阻塞。

    二、消息队列
    1.消息队列中的消息设定为不同类型,又被分配了不同的优先级,新添加的消息总是在队尾,但是接收消息的进程可以读取队列中间的数据。

    2.消息队列降低了读写进程间的耦合强度,若接收消息的进程没有接收到消息,发生消息的进程无须等待,可继续发送消息。消息的读写双方只需要关注各自功能的实现情况即可。

    3.消息队列独立于通信双方的进程之外,若没有删除内核中的消息队列,即便所有使用消息队列的进程都已经终止,消息队列仍存在于内核中,直到内核重新启动,管理命令被执行或调用系统接口删除消息队列时,消息队列才会被真正销毁。

    4.宏的解释:
    MSGMNI:限制系统中的最大消息队列数
    MSGTOL:限制系统中的最大消息数
    MSGMAX:限制消息队列中每个消息中所含数据块的长度
    MSGMNB:限制队列中所含数据块的总长度

    三、信号量
    1.同一个系统中的多个进程之间可能因为进程合作或资源共享而产生制约关系。由于进程合作导致的制约关系称为直接相互制约关系,由于资源共享导致的制约关系称为间接相互制约关系。

    四、共享内存
    1.使用共享内存来实现进程间通信时,通信完成后应释放物理内存,解除进程与共享内存的映射关系
    2.共享内存自身不限制进程对共享内存的读写次序,但程序开发人员应该自觉遵循读写规则,一般情况下,共享内存应与信号量一起使用,由信号量帮它实现读写操作的同步。

    五、实验:
    1.write函数把buf中nbyte写入文件描述符handle所指向的文档中,成功时返回写的字节数,错误时返回-1.

    2.pipe函数创建一个匿名管道,头文件为unistd.h,创建成功则返回0,创建失败则返回-1.

    3.read:从打开的设备或者文件中读取数据。成功则返回读取的字节数,出错则返回-1并设置errno。如果在调用read之前已经到达文件末尾,则这次read返回0.

    4.同步与互斥的区别与联系:出处
    1)互斥:指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排他性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的
    2)同步:指在互斥的基础上,通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源
    3)总的来说,同步是同步是一种复杂的互斥,而互斥是一种特殊的同步,也就是说互斥是两个线程之间不可以同时运行,它们会互相排斥,必须等待一个线程运行完毕,另一个才能运行;而同步也是不能同时运行,但是它必须要以某种次序来运行相应的线程。

    展开全文
  • 实验进程间通信——共享内存

    千次阅读 2019-09-24 00:17:01
    1、了解采用共享内存通信的原理; 2、掌握共享内存的创建及使用方法。 二、实验内容 1、创建写进程,其功能为创建共享内存并映射到当前进程地址空间,然后向内存写入数据,直至遇到’#’为止; 2、读进程使用和...
  • (1) 熟悉并掌握管道机制,并实现进程间通信 (2) 熟悉并掌握共享内存机制,并实现进程间通信 二、实验内容 任务一: (1)阅读以上父子进程利用管道进行通信的例子(例1),写出程序的运行结果并分析。 (2)...
  • 实验要求完成如下任务: 1. 编程实现基于消息缓冲队列机制的进程通信数据结构和 通信原语(创建消息、发送消息、接收消息); 2. 最后编写主函数对所做工作进行测试。
  • Linux软中断通信实验报告实验2 Linux软中断通信1.实验目的通过本实验,掌握软中断的基本原理;掌握中断信号的使用、进程的创建以及系统计时器的使用。2.实验内容(上交的实验2统一取名为:test2由父进程创建两个子...
  • Linux实验报告

    2021-05-10 08:13:27
    课程编号:B080103040Linux操作系统 实验报告姓 名 班 级 实验名称 邵春晓 软工1201 学 号 指 导 教 师 Linux操作系统实验 20124670 石 凯 开 设 学 期 实 验 时 2014-2015第一学期 第11周——第18周 评定人签字 ...
  • OS实验八: 进程间通信实验(一)

    千次阅读 2021-11-11 13:00:27
    2、熟悉LINUX系统中进程之间软中断通信的基本原理 实验内容 编写程序:用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按^c键);捕捉到中断信号后,父进程用系统调用kill()向两...
  • 运行进程管理及进程通信(一)中给出的例子,查看自己运行的结果,并进行分析。  程序1 #include "stdio.h" main() { int i,j,k; if (i=fork()) { j=wait(); printf("Parent Process!\n"); printf("i=%d,j=%d,k=%...
  • 学习如何利用消息缓冲队列进行进程间通信,并加深对消息缓冲队列通信机制的理解。 实验内容: (1) 了解系统调用msgget()、msgsnd()、msgrcv()、msgctl()的功能和实现过程。 (2) 编写一段程序,使其用消息缓冲队列来...
  • 多道程序设计中,经常是若干个进程同时处于就绪状态,必须依照某种策略来决定那个进程...本实验模拟在单处理机情况下的处理机调度问题,加深对进程调度的理解。主要是优先权法、时间片轮转法,结果以画图,表格形式完成
  • 5 基于共享内存的进程间通信-实验1:使用内存映射文件实现进程间通信 一.实验目的 ·使用内存映射文件实现进程通信的方法 ·使用内存映射文件方法加速IO操作的原理 二.实验背景 ·共享内存的基础是内存映射 ·...
  • 操作系统课程实验报告 实习题目 进程间基于消息队列的通信 指导教 学生姓名 学 号 日 期 实现工具 C 语言 实现环境 Linux 系统 实验目的 系统了解linux 系统的通信机构IPC 掌握IPC 中消息通信机 制理解消息通信的...
  • 实验目的 实验原理 实验内容 实验器材 实验步骤
  • 《实验二进程通信-Linux实验报告》由会员分享,可在线阅读,更多相关《实验二进程通信-Linux实验报告(9页珍藏版)》请在人人文库网上搜索。1、实验报告学号_____ 姓名____ ___ 成绩 实验二 进程通信 【实验目的和要求...
  • 管道简介管道是Linux中进程间通信的一种方式,它把一个程序的输出直接连接到另一个程序的输入(其实我更愿意将管道比喻为农村浇地的管子)。Linux的管道主要包括两种:无名管道和有名管道。这一节主要讲无名管道,首先...
  • 进程间通信的总结

    2019-01-31 20:10:05
    Linux中使用较多的进程间通信  1.管道(Pipe)及 有名管道:管道可用于具有亲缘关系进程间的通信,对于有名管道,还具有无亲缘关系进程间的通信。  管道是基于文件描述符的通信方式  注意:当一个管道共享多对...
  • 2016 学年第 1 学期实 验 报 告课程名称: linux编程基础实验名称: linux多进程和进程间通信班 级 学 号:学 生 姓 名: 指 导 教 师日 期: 20 15 年 12 月实验六 linux多进程与进程间通信一、实验目的熟悉linux...
  • 操作系统进程间消息队列通信实验 进程间消息队列通信实验所用函数说明 实现代码如下: #include<stdio.h> #include<sys/types.h> #include<sys/wait.h> #include<sys/msg.h> #include<...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,514
精华内容 3,005
关键字:

进程间通信实验报告

友情链接: PLL.zip