linux 系统编程 进程间通信--IPC(2)附测试代码

1.共享内存

共享内存就是映射一段能被其它进程所访问的内存,这段共享内存由一个进程创建,但其它的多个进程 都可以访问,使得多个进程可以访问同一块内存空间。共享内存是最快的 IPC 方式,它是针对其它进程间通信方式运行效率低而专门设计的,它往往与其它通信机制,譬如结合信号量来使用,以实现进程间的同步和通信。

草稿记录:共享内存中,收、发双方均可查看消息的内容

编程实践:

//创建共享内存及向共享内存些入端
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <stdlib.h>
//int shmget(key_t key, size_t size, int shmflg);
#include <stdio.h>
#include <unistd.h>
int main()
{
    int shmid;
    key_t key;
    key = ftok(".",1);
    char *shmaddr;                                //指向共享内存的变量,通过这个变量访问共享内存

    shmid = shmget(key,1024*4,IPC_CREAT|0666);    //创建4m共享内存 给予可读可写权限
    if(shmid == -1){                            //-1 represent failed
        printf("shmget No ok\n");
        exit(-1);
    }
    shmaddr = shmat(shmid,0,0);                //完成共享内存映射

    printf("shmat Ok\n");

    printf("before strcpy,data:%s",shmaddr);      //为空
    strcpy(shmaddr,"binbin love you");          //向共享内存写入内容
    sleep(4);
    shmdt(shmaddr);                               //卸载共享内存
    shmctl(shmid,IPC_RMID,0);                    //将共享内存从内核关闭 RMID 熟悉的面孔
    return 0;
}

#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <stdlib.h>
//int shmget(key_t key, size_t size, int shmflg);
#include <stdio.h>
#include <unistd.h>
int main()
{
    int shmid;
    key_t key;
    key = ftok(".",1);
    char *shmaddr;

    shmid = shmget(key,1024*4,0);   //获取共享内存
    if(shmid == -1){               //-1 represent failed
        printf("shmget No ok\n");
        exit(-1);
    }
    shmaddr = shmat(shmid,0,0);

    printf("shmat Ok\n");

    printf("data:%s",shmaddr);
    sleep(4);
    shmdt(shmaddr);
    printf("quit\n");
    return 0;
}

补充:终端 查看所有共享内存方法: ipcs -m

 删除指定进程  :ipcs -m  共享内存id号

2.信号

                用于通知接收信号的进程有某种事件发生,所以可用于进程间通信;除了用于进程间通信之外,进程还可以发送信号给进程本身。

动手实现发送信号应用:

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>


int main(int argc,char **argv)
{
    int signum;
    int pid;
    signum = atoi(argv[1]);
    pid = atoi(argv[2]);

    int a = 10;

    union sigval value;
    value.sival_int = a;

    sigqueue(pid,signum,value);//signum 是我们的第二个命令行参数随便输入一个数  是哪个用户的意思  pid是我们的第三个命令行参数
    printf("%d,done\n",getpid());
    return 0;
}

       接收信号:

#include <signal.h>
//int sigaction(int signum, const struct sigaction *act,
//                                   struct sigaction *oldact);
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

void handler(int signum,siginfo_t *info,void*context)
{
    printf("get signum:%d\n",info->si_pid);
    if(context != NULL){
        printf("get data=%d\n",info->si_int);
        printf("get data=%d\n",info->si_value.sival_int);
}
}

int main()
{
    struct sigaction act;
    printf("pid = %d\n",getpid());

    act.sa_sigaction = handler;
    act.sa_flags = SA_SIGINFO;//be able to get massage

    sigaction(SIGUSR1,&act,NULL);
    while(1);
    return 0;


}

 接收信号代码编译为Nicesignal并执行:

发送信号代码编译为Nicesend并执行:./Nicesend 10 15270
运行结果为:

3.消息队列

消息队列是消息的链表, 存放在内核中并由消息队列标识符标识, 消息队列克服了信号传递信息少、 管道只能承载无格式字节流以及缓冲区大小受限等缺陷。 消息队列包括 POSIX 消息队列和 System V 消息队列。消息队列是 UNIX 下不同进程之间实现共享资源的一种机制, UNIX 允许不同进程将格式化的数据流以消息队列形式发送给任意进程, 有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。
写入(读取)队列一方:

#include <stdio.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <string.h>
struct msgbuf{
            long mtype;//消息类型
            char mtext[128];//massage data
};
//ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
//int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//int msgget(key_t key, int msgflg);
int main()
{
    struct msgbuf sendBuf={888,"this is massage from queue"};
    struct msgbuf readBuf;
    key_t key;
    key = ftok(".",'z');
    printf("key:%x\n",key);

    int msg_id = msgget(key,IPC_CREAT|0777);//duiliecsu  meiyoujiuchuangjian duiliehao
  if(msg_id == -1){
        printf("get queue failed\n");
    }
    msgsnd(msg_id,&sendBuf,strlen(sendBuf.mtext),0);
    printf("send over;\n");
    msgrcv(msg_id,&readBuf,sizeof(readBuf.mtext),988,0);
    printf("return from que:%s\n",readBuf.mtext);
    msgctl(msg_id,IPC_RMID,NULL);

//send massage

    return 0;
}

读取(写入)队列一方:

#include <stdio.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <string.h>
struct msgbuf{
            long mtype;//消息类型
            char mtext[128];//massage data
};
//ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
//int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//int msgget(key_t key, int msgflg);
int main()
{
    struct msgbuf sendBuf={888,"this is massage from queue"};
    struct msgbuf readBuf;
    key_t key;
    key = ftok(".",'z');
    printf("key:%x\n",key);


    int msg_id = msgget(key,IPC_CREAT|0777);//创建消息队列并返回队列id
    if(msg_id == -1){
        printf("get queue failed\n");
    }
    msgrcv(msg_id,&readBuf,sizeof(readBuf.mtext),888,0);//sort is 888
    printf("get from que:%s\n",readBuf.mtext);
    struct msgbuf sendbuf={988,"thanks for reach"};
    msgsnd(msg_id,&sendbuf,strlen(sendbuf.mtext),0); 
    msgctl(msg_id,IPC_RMID,NULL);   //发送方需销毁
    return 0;
}

4.信号量

        信号量是一个计数器, 与其它进程间通信方式不大相同, 它主要用于控制多个进程间或一个进程内的多个线程间对共享资源的访问, 相当于内存中的标志,进程可以根据它判定是否能够访问某些共享资源,同时,进程也可以修改该标志, 除了用于共享资源的访问控制外,还可用于进程同步。它常作为一种锁机制(一个进程归还锁、一个进程需要钥匙并归还锁, 防止某进程在访问资源时其它进程也访问该资源, 因此, 主要作为进程间以及同一个进程内不同线程之间的同步手段。 Linux 提供了一组精心设计的信号量接口来对信号量进行操作,它们声明在头文件 sys/sem.h 中,有空可以去研究一下。

  #include <stdio.h>
  #include <sys/types.h>
  #include <sys/ipc.h>
  #include <sys/sem.h>
  #include <unistd.h>

//api:
//int semget(key_t key, int nsems, int semflg);
 //int semctl(int semid, int semnum, int cmd, ...);
  // int semop(int semid, struct sembuf *sops, unsigned nsops);
   
  union semun {
                 int              val;    /* Value for SETVAL */
                 struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
                 unsigned short  *array;  /* Array for GETALL, SETALL */
                 struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                             (Linux-specific) */
  };
  
  void pGetKey(int id)
  {   
      struct sembuf set;
      
      set.sem_num = 0;
      set.sem_op = -1;
      set.sem_flg=SEM_UNDO;
      
      semop(id,  &set ,1);
      printf("getkey\n");
  }
  
  void vPutBackKey(int id)
  {   
      struct sembuf set;
      
      set.sem_num = 0;
      set.sem_op = 1;
      set.sem_flg=SEM_UNDO;
 
      semop(id,  &set ,1);
      printf("put back the key\n");
 }

    int semid;

    key = ftok(".",2);
                       //信号量集合中有一个信号量  
    semid = semget(key, 1, IPC_CREAT|0666);//获取/创建信号量

    union semun initsem;
    initsem.val = 0;
                  //操作第0个信号量   
    semctl(semid, 0, SETVAL, initsem);//初始化信号量
                  //SETVAL设置信号量的值,设置为inisem


    int pid = fork();
    if(pid > 0){
        //去拿锁
    pGetKey(semid);
        printf("this is father\n");
    vPutBackKey(semid);
        //锁放回去
    semctl(semid,0,IPC_RMID);
    }
    else if(pid == 0){
        printf("this is child\n");
    vPutBackKey(semid);
    }else{

        printf("fork error\n");
    }

    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈俊帆Linux_Android

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值