泉缘泉 发表于 2024-8-14 01:14:19

进程间通信—IPC对象通信

一.共享内存(Shared Memory)



[*] 效率:共享内存是进程间通信效率最高的方式。
[*] 操纵流程:

[*]生成唯一的 key 值。
[*]通过 shmget 申请共享内存对象。
[*]使用 shmat 将共享内存映射到当地内存。
[*]读写共享内存。
[*]使用 shmdt 打消映射。
[*]使用 shmctl 删除共享内存对象。

[*]所需头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

[*]key值创建方式:
                   1.IPC_PRIVATE 固定的私有键值,其值等于 0x0,一般用于有亲缘关系的进程间使                            用。
                   2.ftok()创建暂时键值。

1.ftok 函数:



[*] 函数原型:key_t ftok(const char *pathname, int proj_id);
[*] 功能:通过该函数可以将pathname指定的路径用来以proj_id生成唯一的暂时键值。
[*] 参数:pathname 路径+名称->任意文件,只要不会被删除重建即可。
           proj_id 整形的数字,一般用ASCII码的单字符。表现与参数1的运算。
[*] 返回值:成功返回唯一键值,失败为-1。

2.shmget 函数:



[*] 函数原型:int shmget(key_t key, size_t size, int shmflg);
[*] 功能:使用唯一键值key向内核提出共享内存使用申请。
[*] 参数:key 唯一键值。
           size 要申请的共享内存大小。
           shmflg 申请的共享内存访问权限,八进制表现。
                       假如是第一个申请,则用IPC_CREAT;
                       假如要检测是否存在,用IPC_EXCL。
[*] 返回值:成功返回共享内存id,一般用shmid表现,失败为-1。

3.shmat 函数:



[*]函数原型:void *shmat(int shmid, const void *shmaddr, int shmflg);
[*] 功能:将指定shmid对应的共享内存映射到当地内存。
[*] 参数:shmid 要映射的当地内存。
           shmaddr 当地可用的地址,假如不确定则用NULL,表现由系统自动分配。
           shmflg 0,表现读写,SHM_RDONLY表现只读。
[*] 返回值:成功返回映射的地址,一般等于shmaddr,失败为-1。

4.shmdt 函数:



[*]函数原型:int shmdt(const void *shmaddr);
[*] 功能:将当地内存与共享内存断开映射关系。
[*] 参数:shmaddr 要断开的映射地址。
[*] 返回值:成功返回0,失败为-1。

5.shmctl 函数:



[*]函数原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
[*] 功能:修改共享内存属性,也可以删除指定的共享内存对象。
[*] 参数:shmid 要删除的共享内存对象。
           cmd    IPC_RMID 删除对象的宏。
           buf      NULL表现只删除对象。
[*] 返回值:成功返回0,失败为-1。

6.部分题目探究


[*] 共享内存数据的存储方式是拷贝照旧剪切?
       在共享内存的上下文中,数据的存储方式是拷贝(Copy)。当一个进程写入数据到共享内存时,它实际上是将数据从自己的地址空间复制到共享内存地区。同样地,当进程从共享内存读取数据时,它是从共享内存地区复制数据到自己的地址空间。
[*] 共享内存的数据假如多次不同进程读写会怎么样?
        假如多个进程对同一共享内存地区进行读写操纵,而没有适当的同步机制,那么数据可能会被覆盖。比方,假如进程A和进程B都试图写入同一内存位置,而进程B在进程A写入之后立刻写入相同的位置,那么进程A的写入可能会被进程B的写入覆盖。这可能导致数据不同等和竞态条件。
[*] 进程1 写入共享内存,如何通知进程2 读共享内存?
       为了在进程间进行有效的通信,通常需要使用同步机制来确保数据的同等性和同步。这将引出下面有关信号量集的内容。

二.信号量(Semaphore)



[*] 目的:解决共享内存的临界资源访问题目。
[*] 操纵流程:

[*]key值。
[*]使用 semget 申请信号量集。
[*]初始化信号量(P操纵)。
[*]进行PV操纵。
[*]删除信号量。

1.semget 函数:



[*]函数原型:int semget(key_t key, int nsems, int semflg);
[*] 功能:通过唯一键值向内核提出信号量申请。
[*] 参数:key 唯一键值。
           nsems 要申请的信号量个数。
           semflg 申请的信号量的访问权限。
[*] 返回值:成功返回semid,失败为-1。
2.semop 函数



[*] 函数原型:int semop(int semid, struct sembuf *sops, unsigned nsops);
[*] 功能:修改指定信号量会合的信号量的值。
[*] 参数:1)semid 信号量集id。

           2)struct sembuf
          {
              unsigned short sem_num;  ///信号量会合信号量的编号,默认以0开始
              short             sem_op;   ///信号量的PV操纵,假如改值等于-1则表现p        
                                                                                                   等于1 则表现v
                                                                                                   等于0 则表现阻塞
              short          sem_flg;   ///信号量的操纵方式 0 表现默认阻塞。
              IPC_NOWAIT and SEM_UNDO.
          };

          3)nsops 信号量的设置值个数。
[*] 返回值:成功返回0,失败为-1。
[*] 自界说封装:

[*]通常会将以上函数做自界说封装。

int my_sem_wait(int id,int sem)
        {
                struct sembuf mysem;
                mysem.sem_num = sem;
                mysem.sem_op= -1;
                mysem.flg          = 0;

                if(semop(id,&mysem,1) < 0)
                        return -1;
                else
                        return 0;
        }

int my_sem_post(int id,int sem)
        {
                struct sembuf mysem;
                mysem.sem_num = sem;
                mysem.sem_op= 1;
                mysem.flg          = 0;

                if(semop(id,&mysem,1) < 0)
                        return -1;
                else
                        return 0;
        }
3.semctl 函数:



[*]函数原型:int semctl(int semid, int semnum, int cmd, ...);
[*] 功能:根据semid删除指定的信号量集。
[*] 参数:semid 要删除的信号量集。
           semnum 要删除的信号量会合的信号量的编号。
           cmd  IPC_RMID  删除对象宏。
           ...    可变长参数,可以不写。
[*] 返回值:成功返回0,失败为-1。

三.消息队列(Message Queue)



[*]敬请等待。。。。。。

四.辅助命令



[*]ipcs -a:查询共享内存、信号量集、消息队列。
[*]ipcrm -s:删除信号量集。
[*]ipcrm -m:删除共享内存。

五.代码示例

//shm_w.c#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>#include <string.h>int main(int argc, char *argv[]){    key_t key = ftok("./",'!');      if(-1 == key)    {      perror("ftok");      exit(1);    }    printf("key is 0x%x\n",key);    int shmid = shmget(key,4096,IPC_CREAT|0666);    if(-1 == shmid)    {      perror("shmget");      exit(1);    }    void* p =shmat(shmid,NULL,!SHM_RDONLY);    if((void *) -1 == p )    {      perror("shmat");      exit(1);    }    strcpy((char*)p,"hello,this is shm test");    shmdt(p);    return 0;}//shm_r.c#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>#include <string.h>int main(int argc, char *argv[]){    key_t key = ftok("./",'!');      if(-1 == key)    {      perror("ftok");      exit(1);    }    printf("key is 0x%x\n",key);    int shmid = shmget(key,4096,IPC_CREAT|0666);    if(-1 == shmid)    {      perror("shmget");      exit(1);    }    void* p =shmat(shmid,NULL,!SHM_RDONLY);    if((void *) -1 == p )    {      perror("shmat");      exit(1);    }   // strcpy((char*)p,"hello,this is shm test");   printf("mem is %s\n",(char*)p);    shmdt(p);    //shmctl(shmid,IPC_RMID,NULL);    return 0;}

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 进程间通信—IPC对象通信