进程(3)

进程间通信
    基本概念:
        什么是进程间通信:
            是指两个或多个进程之间交互数据的过程,是因为进程之间是相互独立的,为了协同工作的需要必须交互数据
        进程间通信的分类:
            简单的进程间通信:信号、文件、环境变量、命令行参数
            传统的进程间通信:管道文件
            XSI进程间通信:   共享内存、消息队列、信号量
            网络进程间通信:  套接字Socket

传统的进程通信-管道(FIFO):
    管道是UNIX系统中最古老的进程通信方式,古老意味着所有系统都支持,早期的管道文件都是半双工,现有的一些系统的管道是全双工的
    管道是一种特殊的文件,它的数据在文件中是流动的,读取之后就会消失,若文件中没有任何数据,读取时会阻塞

    有名管道:基于有文件名的管道文件的通信
        编程模型:
            进程A                       进程B
           创建管道
           打开管道                    打开管道
           写数据                      读数据
           关闭管道                    关闭管道
           删除管道
        
        创建管道文件:
            1.mkfifo filename
            2.函数
                int mkfifo(const char *pathname, mode_t mode);
                功能:创建有名管道文件
                pathname:管道文件路径
                mode:管道文件权限
        
        匿名管道:
            注意:匿名管道只适合通过fork创建的的父子进程之间使用
            int pipe(int pipefd[2]);
            功能:创建一个匿名管道文件,返回管道文件的读权限fd和写权限fd
            pipefd:返回用于存储管道文件读写fd的数组,输出型参数
                pipefd[0]   用于读
                pipefd[1]   用于写
            
            编程模型:
                父进程              子进程
            获取一对fd              共享了一对fd
            关闭读                  关闭写
            写数据                  读数据
            关闭写                  关闭写

XSI进程间通信:
    X/Open公司指定用于进程之间通信的系统接口
    XSI进程间通信技术都需要借助系统内核,需要创建内核对象,内核对象会以整数形式返回给用户态,相当于文件描述符,也叫做IPC标识符
    文件的创建、打开需要借助文件名,同样的,IPC内核对象创建需要借助IPC键值(整数),必须要确保IPC键值是独一无二的

    #include <sys/types.h>
    #include <sys/ipc.h>
    key_t ftok(const char *pathname, int proj_id);
    功能:计算出一个独一无二的IPC键值
    pathname:项目路径,不是依靠字符串计算,而是依靠路径的位置以及项目编号计算的,所以不能提供加路径,否则可能产生同样的IPC键值
    proj_id:项目编号
    返回值:计算出来的IPC值

共享内存:
    基本特点:
        两个或多个进程之间共享一块内存,该内存可与多个进程的虚拟内存进行映射
        优点:不需要复制信息,是最快的IPC通信机制
        缺点:需要考虑同步访问的问题,一般需要借助信号 来解决

        #include <sys/ipc.h>
        #include <sys/shm.h>
        int shmget(key_t key, size_t size, int shmflg);
        功能:创建、获取共享内存
        key:由进程提供的一个独一无二的IPC键值
        size:共享内存的大小,获取时,该参数无效,一般给0
        shmflag:
            IPC_CREAT       创建共享内存
            IPC_EXCL        共享内存如果已存在,则返回失败
            获取时直接给0
            mode_flags      创建共享内存时需要提供权限, IPC_CREAT|0644
            返回值:IPC标识符,错误返回-1
        
        #include <sys/types.h>
        #include <sys/shm.h>
        
        void *shmat(int shmid, const void *shmaddr, int shmflg);
        功能:让虚拟内存与共享内存隐射
        shmid:IPC标识符
        shmaddr:想要映射的虚拟内存首地址,为NULL时系统回自动操作
        shmflag:
            SHM_RDONLY:         以只读方式映射共享内存
            SHM_RND:           只有当shmaddr参数不为NULL时有效,表示对shaddr参数向下取内存页的整数倍,作为映射地址
                                如果都不需要,则写0
            返回值:与共享内存映射后的虚拟内存首地址,失败返回(void *)-1或者 0xFFFFFFFF
        int shmdt(const void *shmaddr);
        功能:取消映射
        shmaddr:映射过的虚拟内存数首地址

        int shmctl(int shmid, int cmd, struct shmid_ds *buf);
        功能;删除、控制共享内存
        shmid:IPC标识符
        cmd:
            IPC_SET     设置共享内存属性,buf为输入型参数
            IPC_RMID    删除共享内存,buf为NULL
            SHM_STAT    获取共享内存属性,buf为输出型参数
        buf:
         struct shmid_ds {
               struct ipc_perm shm_perm;    //所有者的相关信息
               size_t          shm_segsz;   //共享内存的字节数
               time_t          shm_atime;   //最后映射的时间
               time_t          shm_dtime;   //最后取消映射的时间
               time_t          shm_ctime;   //最后改变的时间
               pid_t           shm_cpid;    //创建者的进程号
               pid_t           shm_lpid;    //最后映射、取消映射者的进程号
               shmatt_t        shm_nattch;  //当前映射的次数
               ...
           };

        struct ipc_perm {
               key_t          __key;    //创建共享内存的IPC键值
               uid_t          uid;      //当前使用共享内存的用户ID
               gid_t          gid;      //当前使用共享内存的组ID
               uid_t          cuid;     //创建共享内存的用户ID
               gid_t          cgid;     //创建共享内存的用户组ID
               unsigned short mode;     //共享内存的权限
               unsigned short __seq;    //共享内存的序列号
           };
    编程模型:
        进程A                               进程B
      创建共享内存                       获取共享内存
      映射共享内存                       映射共享内存
      写数据并通知其他进程                接收到通知后读数据
      接收到通知后读数据                 写数据并通知其他进程
      取消映射                          取消映射
      删除共享内存

消息队列:
    基本特点:
        由内核维护管理的数据链表,是通过消息类型收发数据
        #include <sys/types.h>
        #include <sys/ipc.h>
        #include <sys/msg.h>
        int msgget(key_t key, int msgflg);
        功能:创建、获取消息队列
        key:IPC键值
        msgflg:
            IPC_CREAT       创建消息队列
            IPC_EXCL        如果消息队列已存在,则返回错误
            mode:           当创建消息队列时需要提供权限
        返回值:成功返回IPC标识符,失败返回-1

        int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
        功能:向消息队列发送数据
        msqid:IPC标识符
        msgp:要发送的消息首地址
            struct msgbuf {
               long mtype;       /*消息类型 */
               char mtext[n];    /* 数据 */
           };
        msgsz:数据的字节数,是不包含信息类型的
        msgflg:
            阻塞一般写0
            IPC_NOWAIT      当消息队列满是,不等待立即返回

        ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
        功能:从消息队列中读取数据
        msqid:IPC标识符
        msgp:存储数据结构体首地址
        msgsz:数据结构体的字节数
        msgtyp:要读取的消息的类型,按照类型的数值来读取消息,而不是按照顺序
            >0          读取消息队列中第一条等于msgtyp的消息
            =0          读取消息队列中的第一条消息
            <0          读取消息类型小于abs(msgtyp)的消息,如果有多个满足,则读取值最小的
        msgflg:
            IPC_NOWAIT  消息类型不符合时不阻塞,立即返回
            MSG_EXCEPT  如果msgtyp>0,则读取第一个消息类型不是msgtyp的消息
            MSG_NOERROR 如果不包含此标记,当消息的实际长度>msgsz,则会返回错误,并且读取失败;如果包含此标记,则最多读取msgsz个字节,确保一定成功
        返回值:成功读取到的字节数

        int msgctl(int msqid, int cmd, struct msqid_ds *buf);
        功能:删除、控制消息队列
        msqid:IPC标识符
        cmd:
            SHM_STAT    获取消息队列属性,buf为输出型参数
            IPC_SET     设置消息队列属性,buf为输入型参数
            IPC_RMID    删除消息队列,buf为NULL
        buf:
        struct msqid_ds {
            struct ipc_perm msg_perm;     // 属主信息
            time_t          msg_stime;    // 最后发送时间
            time_t          msg_rtime;    // 最后接收时间
            time_t          msg_ctime;    // 最后修改时间
            unsigned long   __msg_cbytes; // 当前消息队列字节数
            msgqnum_t       msg_qnum;     // 当前的消息数量
            msglen_t        msg_qbytes;   // 消息的最大字节数
            pid_t           msg_lspid;    // 最后发送者的PID
            pid_t           msg_lrpid;    // 最后接收者的PID
        };
    编程模型:
        进程A                       进程B
    创建消息队列                    获取消息队列
    发送消息                        接收消息
    接收消息                        发送消息
    删除消息队列                    

信号量:
    基础概念:
        由内核维护并共享的一个“全局变量”,用于记录共享资源的数量   ,限制进程对共享资源的访问
        信号量是一种操作锁,本身不具备数据交换功能 ,而是通过控制其他的通信资源来实现进程间的协调通信
    1.若信号量的值大于0,说明有可以使用的资源,需要将信号量-1再使用
    2.若信号量的资源等于0,说明没有资源可以使用,此时进程会进入休眠,直到信号量的值大于0,程序会自动唤醒,再重复步骤1、2
    3.当资源使用完毕,需要将信号量的值+1,唤醒其他正在休眠的进程
        #include <sys/types.h>
        #include <sys/ipc.h>
        #include <sys/sem.h>

        int semget(key_t key, int nsems, int semflg);
        功能:创建、获取一个信号量
        key:IPC键值
        nsems:信号量的数量,一般给1即可
        msgflg:
            IPC_CREAT       创建信号量
            IPC_EXCL        如果信号量已存在,则返回错误
            mode:           当创建信号量时需要提供权限
        返回值:成功返回IPC标识符,失败返回-1    

        int semop(int semid, struct sembuf *sops, unsigned nsops);
        功能:对信号量进行加减操作
        semid:IPC标识符,代表了要操作的信号量
        sops:
        struct sembuf
        {
            unsigned short sem_num;  /* 信号量下标 */
            short          sem_op;   
            /*  1           信号量+1
                -1          若信号量值为0,不能-1,则阻塞
                0           等待信号量的值为0  */
            short          sem_flg;  
            /*  IPC_NOWAIT      不阻塞
                SEM_UNDO        如果进程终止没有返还信号量,系统会自动返回  */
        }

        int semctl(int semid, int semnum, int cmd, ...);
        功能:删除、控制信号量
        semid:IPC标识符,代表了要操作的信号量
        semnum:第几个信号量,下标从0开始
        cmd:
            SHM_STAT    获取信号量属性,buf为输出型参数
            IPC_SET     设置信号量属性,buf为输入型参数
            IPC_RMID    删除信号量,buf为NULL
            GETALL      获取所有信号量的值
            GETNCNT     获取等待减信号量的进程数量(休眠进程)
            GETVAL      通过返回值获取某个信号量的值
            GETZCNT     获取等待信号量为0的进程数量
            SETALL      设置所有的信号量的值
            SETVAL      设置某个信号量的值
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,以下是C++模拟的代码: ```c++ #include <iostream> #include <vector> #include <ctime> using namespace std; // 进程结构体 struct Process { int id; // 进程ID int status; // 进程状态,0:阻塞,1:就绪,2:执行 int executeTime; // 执行时间 int priority; // 优先级 int blockTime; // 阻塞时间 Process(int i, int e, int p) { id = i; status = 1; executeTime = e; priority = p; blockTime = 0; } }; vector<Process> processList; // 进程列表 // 创建进程 void createProcess() { int id, executeTime, priority; cout << "请输入进程ID、执行时间和优先级,以空格隔开:"; cin >> id >> executeTime >> priority; Process p(id, executeTime, priority); processList.push_back(p); cout << "成功创建进程!" << endl; } // 阻塞进程 void blockProcess() { int id; cout << "请输入要阻塞的进程ID:"; cin >> id; for (int i = 0; i < processList.size(); i++) { if (processList[i].id == id && processList[i].status == 2) { processList[i].status = 0; processList[i].blockTime = time(NULL); cout << "成功阻塞进程!" << endl; return; } } cout << "进程不存在或进程未执行!" << endl; } // 执行进程 void executeProcess() { int id; cout << "请输入要执行的进程ID:"; cin >> id; for (int i = 0; i < processList.size(); i++) { if (processList[i].id == id && processList[i].status == 1) { processList[i].status = 2; cout << "成功执行进程!" << endl; return; } } cout << "进程不存在或进程已执行或阻塞!" << endl; } // 唤醒第一个阻塞进程 void wakeUpProcess() { for (int i = 0; i < processList.size(); i++) { if (processList[i].status == 0) { processList[i].status = 1; cout << "成功唤醒进程!" << endl; return; } } cout << "没有阻塞的进程!" << endl; } // 执行进程时间片到 void timeOut() { bool flag = false; for (int i = 0; i < processList.size(); i++) { if (processList[i].status == 2) { processList[i].status = 1; flag = true; cout << "时间片到,成功切换进程!" << endl; break; } } if (!flag) { cout << "没有正在执行的进程!" << endl; } } // 终止进程 void killProcess() { int id; cout << "请输入要终止的进程ID:"; cin >> id; for (int i = 0; i < processList.size(); i++) { if (processList[i].id == id) { processList.erase(processList.begin() + i); cout << "成功终止进程!" << endl; return; } } cout << "进程不存在!" << endl; } // 查看进程 void viewProcess() { cout << "当前进程列表:" << endl; cout << "ID\t状态\t执行时间\t优先级\t阻塞时间" << endl; for (int i = 0; i < processList.size(); i++) { cout << processList[i].id << "\t"; if (processList[i].status == 0) { cout << "阻塞\t"; } else if (processList[i].status == 1) { cout << "就绪\t"; } else { cout << "执行\t"; } cout << processList[i].executeTime << "\t" << processList[i].priority << "\t" << processList[i].blockTime << endl; } } // 查看内存占用情况 void viewMemory() { cout << "内存占用情况:" << endl; cout << "进程ID\t执行时间" << endl; for (int i = 0; i < processList.size(); i++) { cout << processList[i].id << "\t" << processList[i].executeTime << endl; } } int main() { int choice; while (true) { cout << "请输入要进行的操作:1.创建进程 2.阻塞执行进程 3.执行进程 4.唤醒阻塞进程 5.执行进程时间片到 6.终止进程 7.查看进程 8.查看内存占用情况 0.退出" << endl; cin >> choice; switch (choice) { case 0: return 0; case 1: createProcess(); break; case 2: blockProcess(); break; case 3: executeProcess(); break; case 4: wakeUpProcess(); break; case 5: timeOut(); break; case 6: killProcess(); break; case 7: viewProcess(); break; case 8: viewMemory(); break; default: cout << "无效的操作!" << endl; break; } } return 0; } ``` 这个模拟程序实现了创建进程、阻塞执行进程、执行进程、唤醒第一个阻塞进程、执行进程时间片到、终止进程、查看进程和查看内存占用情况等功能。你可以根据需要进行修改和扩展。 ### 回答2: 1.创建进程:创建进程是指在计算机系统中新建一个现有程序的实例,以便在操作系统的管理下独立运行。创建进程的方式可以是通过系统调用或者其他进程通过fork()或exec()等函数创建。 2.阻塞执行进程:当一个进程需要等待某些事件发生时,可以选择阻塞自己的执行,让其他进程占用CPU资源。阻塞执行进程通常是通过调用系统函数或者等待一个信号量来实现。 3.执行进程:执行进程是指操作系统从就绪队列中选择一个进程,并分配CPU资源给该进程执行。在一个多道程序系统中,有多个进程可以执行,操作系统通过调度算法来选择下一个要执行的进程。 4.唤醒第一个阻塞进程:当一个等待事件发生的进程收到事件信号时,操作系统会将其从阻塞状态转为就绪状态,并放入就绪队列中。一旦进程被唤醒,它就可以参与到CPU资源的竞争中来。 5.执行进程时间片到:为了公平地分配CPU资源,操作系统通常会采用时间片轮转的调度算法。当一个进程的时间片用完后,操作系统会剥夺该进程的CPU控制权,并将其重新放入就绪队列中等待下一轮调度。 6.终止进程:当一个进程完成了它的任务,或者出现了无法继续执行的错误,操作系统就会将其终止。终止进程的方式可以通过调用exit()函数或者发送终止信号来实现。 7.查看进程:在操作系统中,可以通过系统工具或者命令来查看当前运行的进程信息,包括进程ID、进程状态、占用的CPU和内存等。 8.查看内存占用情况:了解计算机系统中内存的使用情况对于性能优化和故障排除非常重要。可以通过系统工具或者命令来查看当前内存占用的情况,包括已使用内存、空闲内存以及内存交换等信息。 ### 回答3: 1. 创建进程:当操作系统接收到一个新的任务时,会为该任务创建一个新的进程。创建进程的过程包括为该进程分配独立的内存空间、创建相应的数据结构等。 2. 阻塞执行进程:当一个进程发起某些阻塞型操作,如等待用户输入或等待某个资源就绪时,该进程会被标记为阻塞状态,暂停执行,直到满足相应的条件。 3. 执行进程:处于就绪状态的进程会被调度器选择并执行。执行进程时,操作系统会分配给该进程一定的CPU时间片,进程利用这段时间执行其指定的任务。 4. 唤醒第一个阻塞进程:当被阻塞的进程所需资源就绪后,操作系统会将其唤醒,使其重新进入就绪状态,并等待调度器选择执行。 5. 执行进程时间片到:每个进程在执行时都有一个时间片,当其时间片用完后,操作系统会将其状态设置为就绪状态,并选择下一个进程执行。 6. 终止进程:当一个进程完成了其任务,或者发生了错误、崩溃等情况时,操作系统会将其标记为终止状态,并释放其占用的资源。 7. 查看进程:操作系统提了一些工具或命令,可以用来查看当前正在运行的进程,可以查看进程进程ID、进程状态、所占用的资源等信息。 8. 查看内存占用情况:操作系统提了相应的工具或命令,可以用来查看当前内存的使用情况,包括已使用的内存量、剩余的内存量等信息。通过查看内存占用情况,可以及时调整进程的内存分配,以提高系统的性能和效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值