目录

  • 了解
  • 使用管道来通信
    • 无名管道
    • 有名管道
  • 消息队列
    • key 键值生成
  • 共享内存
  • 信号
    • 信号概述
    • 信号如何携带消息
    • 信号发送函数:
  • 信号量

了解

创建进程后实现父子通讯的连接。
我们希望有一个管道来进行数据的交互。之前可以用exit和exec族函数来假通信。数据很有限。
所以我们使用IPC,进程的通信。

使用管道来通信

无名管道

进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。
IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC。

https://blog.csdn.net/baidu_38621657/article/details/105724822>

怎么理解半双工呢:父写数据在管道,子进程读。在同一时间,父子只能一个读,一个写。
且!:管道中的数据读走之后就没有了。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{int fd[2];int pid;char buf[128];if(pipe(fd) == -1){printf("创建管道失败!\n");}pid = fork();if(pid < 0){printf("进程创建失败!\n");}else if(pid > 0){printf("我是董瑞龙的父亲\n");close(fd[0]);//ssize_t write(int fd, const void *buf, size_t count);write(fd[1],"Ha Ha ha!\n",strlen("Ha Ha ha!"));wait();}else{printf("董瑞龙我儿!\n");close(fd[1]);//ssize_t read(int fd, void *buf, size_t count);read(fd[0],buf,128);printf("read data is %s\n",buf);exit(0);}return 0;
}

有名管道

FIFO、、使用mkfifo

与无名管道原理一样

当 open 一个FIFO时,是否设置非阻塞标志(O_NONBLOCK)的区别:

  • 若没有指定O_NONBLOCK(默认),只读 open 要阻塞到某个其他进程为写而打开此 FIFO。类似的,只写 open 要阻塞到某个其他进程为读而打开它。
  • 若指定了O_NONBLOCK,则只读 open 立即返回。而只写 open 将出错返回 -1 如果没有进程已经为读而打开该 FIFO,其errno置ENXIO。

消息队列

消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
特点

  • 消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
  • 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
  • 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
1 #include <sys/msg.h>
2 // 创建或打开消息队列:成功返回队列ID,失败返回-1
3 int msgget(key_t key, int flag);
4 // 添加消息:成功返回0,失败返回-1
5 int msgsnd(int msqid, const void *ptr, size_t size, int flag);
6 // 读取消息:成功返回消息数据的长度,失败返回-1
7 int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
8 // 控制消息队列:成功返回0,失败返回-1
9 int msgctl(int msqid, int cmd, struct msqid_ds *buf);

这里要记住一个api:msgctl函数。作用是关闭队列。RMID:从内核中移除。

key 键值生成

ftok,去内核找到相关id 第一个是路径名,第二个是…随意
ls-ai id值通过十六进制计算。

各种通信方式的不同: 管道就像一个通道,信息就像上课传的小纸条(有去无回),比如你给女神表白她一直不回你。
消息队列就像一个箱子,可以放进去可以看,看完再把东西放进去。这种可以双方通信,比较优势。 共享内存是什么呢?
我可以给我的女神同桌在桌子上表白,女神可以马上看到。在内存中有一块公共内存,我和女神都可以看到。

共享内存

1:创建共享内存。
2:映射。(干掉)

1、shm函数(创建共享内存)
函数声明:
int shmget(key_t ey,size_t size, int shmflg);
第一个参数key:为共享内存段命名,有一个特殊的键值IPC_PRIVATE,用于创建一个只属于创建进程的共享内存
第二个参数size:是共享内存的大小(字节数)
第三个参数shmflg:包含9个比特的权限标志,作用同文件操作是的mode标志位相同
返回值:函数执行成功返回一个非负整数,即内存标识符,失败时返回-1.
2、shmat函数(将共享内存连接到进程)第一次创建共享内存段,该共享内存段并不能被任何进程所使用,只有当共享内存被连接到一个进程,才可以访问共享内存,这个功能由shmat函数实现。
函数声明:
void *shmat(int shm_id, const oid *shm_addr, int shmflg);
第一个参数:所要连接的共享内存标识符。
第二个参数:指定共享内存连接到当前进程的地址位置,一般传NULL,表示由系统选择共享内存连接的位置。
第三个参数:可取SHM_RND和SHM_RDONLY(使得连接的内存地址只读)
返回值:函数执行成功返回共享内存的首地址,失败返回-1
3、shmdt函数(分离共享内存)该函数的参数是shmat函数返回的共享内存地址指针,成功返回0,失败返回-1.
4、shmctl(控制函数)
函数声明:
int shmctl(int shm_id, int command, struct shmid_ds *buf);
第一个参数:共享内存标识符
第二个参数://要采取的动作,有如下取值:IPC_STAT:把shm_ds结构中的数据设置为共享内存的当前关联值IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构体中的值IPC_RMID:删除共享内存。
第三个参数:buf是一个指针,指向包含共享内存模式和访问权限的结构
返回值:成功返回0失败返回-1.
struct shmid_ds
{uid_t shm_perm.uid;   uid_t shm_perm.gid;    mode_t shm_perm.mode;
}

https://blog.csdn.net/qq_41727218/article/details/82772056

shmat使用时后面俩个变量写0,一个是让Linux自动分配共享内存,另一个是权限。

信号

类似于51的定时器,一种信号来中断你现在处理的事情,信号也有优先级。在Linux实际上是软中断,51是硬中断。

信号概述

1.信号的名字和编号:

每个信号都有一个名字和编号,这些名字都以“SIG”开头,例如“SIGIO ”、“SIGCHLD”等等。
信号定义在signal.h头文件中,信号名都定义为正整数。
具体的信号名称可以使用kill -l来查看信号的名字以及序号,信号是从1开始编号的,不存在0号信号。kill对于信号0又特殊的应用。

2.信号的处理:

信号的处理有三种方法,分别是:忽略、捕捉和默认动作

  • 忽略信号,大多数信号可以使用这个方式来处理,但是有两种信号不能被忽略(分别是
    SIGKILL和SIGSTOP)。因为他们向内核和超级用户提供了进程终止和停止的可靠方法,如果忽略了,那么这个进程就变成了没人能管理的的进程,显然是内核设计者不希望看到的场景
  • 捕捉信号,需要告诉内核,用户希望如何处理某一种信号,说白了就是写一个信号处理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调用用户自定义的函数,以此来实现某种信号的处理。
  • 系统默认动作,对于每个信号来说,系统都对应由默认的处理动作,当发生了该信号,系统会自动执行。不过,对系统来说,大部分的处理方式都比较粗暴,就是直接杀死该进程。具体的信号默认动作可以使用man 7 signal来查看系统的具体定义。

其实对于常用的 kill 命令就是一个发送信号的工具,kill 9 PID来杀死进程。比如,我在后台运行了一个 top 工具,通过 ps
命令可以查看他的 PID,通过 kill 9 来发送了一个终止进程的信号来结束了 top 进程。如果查看信号编号和名称,可以发现9对应的是
9) SIGKILL,正是杀死该进程的信号。而以下的执行过程实际也就是执行了9号信号的默认动作——杀死进程。

下面我们可以自己实现对Linux命令ctrl c的改写并通过软件编程实现对进程的kill。

#include <signal.h>
#include <stdio.h>void change(int num)
{printf("get num is = %d\n",num);printf("quit is useless!");
}int main()
{signal(SIGINT,change);while(1);return 0;
}
这是阻止Linux   shell命令ctrl c 的代码

那么我们如何自己去解锁呢?

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>int main(int argc , int **argv)
{int num;int pid;num = atoi(argv[1]);pid = atoi(argv[2]);printf("argc is %d\n",argc);printf("num=%d,pid=%d\n",num,pid);kill(pid,num);printf("welldone!\n");return 0;
}
~     这是删除命令


那么完成之后,删除命令也是可以优化的:使用system函数

信号如何携带消息

入门版:函数signal
高级版:函数sigaction
sigaction 的函数原型:创建

#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);struct sigaction {void       (*sa_handler)(int); //信号处理程序,不接受额外数据,SIG_IGN 为忽略,SIG_DFL 为默认动作void       (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序,能够接受额外数据和sigqueue配合使用,第三个指针非空代表有数据。sigset_t   sa_mask;//阻塞关键字的信号集,可以再调用捕捉函数之前,把信号添加到信号阻塞字,信号捕捉函数返回之前恢复为原先的值。int        sa_flags;//影响信号的行为SA_SIGINFO表示能够接受数据};
//回调函数句柄sa_handler、sa_sigaction只能任选其一
 siginfo_t {int      si_signo;    /* Signal number */int      si_errno;    /* An errno value */int      si_code;     /* Signal code */int      si_trapno;   /* Trap number that causedhardware-generated signal(unused on most architectures) */pid_t    si_pid;      /* Sending process ID */uid_t    si_uid;      /* Real user ID of sending process */int      si_status;   /* Exit value or signal */clock_t  si_utime;    /* User time consumed */clock_t  si_stime;    /* System time consumed */sigval_t si_value;    /* Signal value */int      si_int;      /* POSIX.1b signal */void    *si_ptr;      /* POSIX.1b signal */int      si_overrun;  /* Timer overrun count; POSIX.1b timers */int      si_timerid;  /* Timer ID; POSIX.1b timers */void    *si_addr;     /* Memory location which caused fault */int      si_band;     /* Band event */int      si_fd;       /* File descriptor */
}

信号发送函数:

#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);
union sigval {int   sival_int;void *sival_ptr;};

下面是通过信号来实现消息的发送与接受:

#include <signal.h>
#include <stdio.h>//int sigaction(int signum, const struct sigaction *act,//struct sigaction *oldact);void doo(int num,siginfo_t *info,void *context)
{printf("get signum = %d\n",num);if(context != NULL){printf("get data = %d\n",info->si_int);printf("get data = %d\n",info->si_value.sival_int);//俩种数据获取方式printf("data from %d\n",info->si_pid);}
}int main()
{struct sigaction act;printf("get pid = %d\n",getpid());act.sa_sigaction = doo;act.sa_flags = SA_SIGINFO;//可以接受到消息sigaction(SIGUSR1,&act,NULL);while(1);return 0;
}
这是收
#include <stdio.h>
#include <signal.h>int main(int argc ,char **argv)
{int num;int pid;num = atoi(argv[1]);pid = atoi(argv[2]);union sigval value;value.sival_int = 520;sigqueue(pid,num,value);printf("getpid = %d\n",getpid());return 0;
}
这是发,可以更改为字符串消息

信号量

信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。
简单的说就是管理,比如控制共享内存一个读一个写,不同时进行。
信号量集。分为p操作和v操作。

1 #include <sys/sem.h>
2 // 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
3 int semget(key_t key, int num_sems, int sem_flags);
4 // 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
5 int semop(int semid, struct sembuf semoparray[], size_t numops);
6 // 控制信号量的相关信息
7 int semctl(int semid, int sem_num, int cmd, ...);1 struct sembuf
2 {3     short sem_num; // 信号量组中对应的序号,0~sem_nums-1
4     short sem_op;  // 信号量值在一次操作中的改变量
5     short sem_flg; // IPC_NOWAIT, SEM_UNDO
6 }

semget函数:
第二个参数是信号量集信号量的个数,第三个跟共享内存一样,可以使用IPC_CREAT|0600,
semctl函数:
第一个是操作量级id,第二代表要操作第几个信号量,第三个参数可以使用SETVAL来设置初值,根据man 要求定义联合体

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) */
};

// P操作://    若信号量值为1,获取资源并将信号量值-1
//    若信号量值为0,进程挂起等待int sem_p(int sem_id)
{struct sembuf sbuf;sbuf.sem_num = 0; /*序号*/信号量编号sbuf.sem_op = -1; /*P操作*/操作无法进入sbuf.sem_flg = SEM_UNDO;//等待if(semop(sem_id, &sbuf, 1) == -1){perror("P operation Error");return -1;}return 0;}// V操作://    释放资源并将信号量值+1//    如果有进程正在挂起等待,则唤醒它们int sem_v(int sem_id){struct sembuf sbuf;sbuf.sem_num = 0; /*序号*/sbuf.sem_op = 1;  /*V操作*/sbuf.sem_flg = SEM_UNDO;if(semop(sem_id, &sbuf, 1) == -1){perror("V operation Error");return -1;}return 0;}

进程间的通信方式(管道,消息队列,共享内存,信号)相关推荐

  1. msgget();msgsnd();msgrcv();msgctl(); 消息队列 Linux进程间的通信方式之消息队列

    Linux进程间的通信方式 ----消息队列. 消息队列和共享内存类似 消息队列它允许一个或多个进程向它写消息,一个或多个进程向它写读消息. 消息队列存在于系统内核中,消息的数量受系统限制. 我们来看 ...

  2. 【Linux】进程间通信 —— 匿名管道 | 命名管道 | System V | 消息队列 | 共享内存

    进程间通信 0. 进程间通信 1. 管道 1.1 匿名管道 1.1.1 匿名管道原理 1.1.2 创建匿名管道pipe 1.1.3 基于匿名管道通信的4种情况5个特点 1.2 命名管道 1.2.1 创 ...

  3. Linux 进程间通讯(IPC)方式 ------- 共享内存

    Linux 进程间通讯(IPC)方式有以下几种: 1->管道(pipe)和有名管道(fifo). 2->消息队列 3->共享内存 4->信号量 5->信号(signal) ...

  4. 1、几种进程间的通信方式

    1.几种进程间的通信方式 # 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系通常是指父子进程关系. # 有名管道 (named ...

  5. Windows进程间各种通信方式浅谈(转)

    转自 https://blog.csdn.net/microzone/article/details/7044266 权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原 ...

  6. 【Linux篇】第十二篇——进程间通信(管道+system V共享内存)

    进程间通信介绍 概念 目的 本质 分类 管道 什么是管道 匿名管道 匿名管道的原理 pipe函数 匿名管道使用步骤 管道读写规则 管道的特点 管道的大小 命名管道 命名管道的原理 使用命令创建命名管道 ...

  7. 进程间基于消息队列的通信_Linux 进程间的通信方式

    (一)进程的概念 进程是操作系统的概念,每当我们执行一个程序时,对于操作系统来讲就是创建一个进程,在这个 过程中伴随着资源的分配和释放,可以认为进程是一个程序的一次执行过程. (二)进程间通信的概念 ...

  8. 共享内存(进程间的通信方式)

    目录 1.共享内存的特点 2.函数接口 3.有关共享内存的系统命令 1.共享内存的特点 (1)共享内存是一种最高效的进程间的通信方式,进程可以直接读写内存,而进程之间不需要通过任何数据的拷贝. (2) ...

  9. 几种进程间的通信方式

    # 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系通常是指父子进程关系. # 有名管道 (named pipe) : 有名管道也 ...

最新文章

  1. 干货|TensorFlow开发环境搭建(Ubuntu16.04+GPU+TensorFlow源码编译)
  2. 深掘市场 开拓机遇 西部数据将亮相2014年北京安博会
  3. 可能是最全面的G1学习笔记
  4. vb.net 如何文件指定打印机打印文件_使用Dropbox文件请求配合Canon Inkjet实现多用户文件打印...
  5. PYTHON得到pdf页数、遍历当前文件夹
  6. switch语句使用注意事项
  7. c#正则表达式取出数据库中带html标签的内容,C#用正则表达式 获取网页源代码标签的属性或值...
  8. html盒子模型子元素怎么水平占满父元素_立下flag)每日10道前端面试题18 关于【盒模型】十问...
  9. ...为他们的产品痴迷,不是有兴趣,不是了解,而是痴迷
  10. 微信小程序云开发教程-小程序在云开发下的运作模式
  11. vfp spt连接mysql_VFP与SQL远程异构数据库
  12. 集美大学计算机课程考试系统,集美大学教务管理系统入口http://jwgl3.jmu.edu.cn
  13. 简历制作器App使用条款
  14. infer的用法_词汇精选:infer的用法和辨析
  15. level2行情接口怎么用?
  16. 【仿写网站】用swiper实现故宫博物院首页轮播图
  17. 计算机硬件调查和报价600字,600字调查报告.docx
  18. Tableau实现世界GDP排名动态图
  19. 非常好的免费开源网站原型图设计工具
  20. vue搜索(不区分大小写)通用

热门文章

  1. roku能不能安装软件_如何在Roku上更改家长控制PIN
  2. 【理论恒叨】【立体匹配系列】经典SGM:(3)代价聚合(Cost Aggregation)
  3. 【菜鸟读论文】2019_Guided Stereo Matching
  4. 解析巧用因果法破解GRE填空
  5. JVM之垃圾回收算法
  6. Win11遇到问题需要重启怎么办?
  7. autocad2007二维图画法_CAD二维图形绘制的教程
  8. stax2 jar 包冲突
  9. Qt/C++ 开发Android平台《林中伊人》消球小游戏全记录4——半个美工的诞生
  10. AIX下磁带机共享问题