学习进程的创建和释放之后,我们将关心的是进程之间应该如何通讯,下面介绍一下进程之间通讯的三种常用的方法:
1、管道通讯(FIFO)
FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存储文件系统中。命名管道是一个设备文件,因此即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相互通信。
(1)、创建FIFO
#define MKFIFO_FILE"/tmp/sharefile"
int ret = mkfifo(MKFIFO_FILE,0666|O_CREAT);
if(ret<0){
if(errno == EEXIST){
printf("writer find file exist,do nothing\n");
}else {
perror("writer find err");
exit(-3);
}
} int fd = open("/tmp/sharefile",O_RDWR);
if(fd<0){
perror("reader open err");
exit(0);
}
int mkfifo(路径名字char *path, 文件权限flags )
#include
#include
int mkfifo(const char *pathname, mode_t mode);
pathname:你要创建的文件名字,一般放在/tmp/
mode:
返回值:
0-success
-1: errno
EACCES ,没有权限
EEXIST, 文件已存在
(2)、创建一个FIFO,可以理解为创建了一个文件,我们可以用两个不同的进程来打开文件,对文件进行操作等等。采取一个进程存储,一个进程进行读取数据就可以达到通讯的效果。
//写数据
#include #include
#include
#include
#include #include
#include
#include #define MKFIFO_FILE"/tmp/sharefile"struct msg_struct{
char sex;
char name[32];
int age;
long weight;
//......................
};
int main()
{
int ret = mkfifo(MKFIFO_FILE,0666|O_CREAT);
if(ret<0){
if(errno == EEXIST){
printf("writer find file exist,do nothing\n");
}else {
perror("writer find err");
exit(-3);
}
}
int fd = open("/tmp/sharefile",O_RDWR);
if(fd<0){
perror("writer open err");
exit(0);
}
struct msg_struct writemsg;
while(1){
writemsg.sex='M';
strcpy(writemsg.name,"xiaowang");
writemsg.age=12;
writemsg.weight=102;
/*
如果管道fifo fd中,暂时没有数据,read会在函数内部阻塞等待数据
*/
ret = write(fd,&writemsg,sizeof(writemsg));
if(ret<0){
perror("writer read err");
return -34;
}sleep(1);
}
close(fd);
/*删除该文件*/
unlink("/tmp/sharefile");
}
·
//读数据
#include #include
#include
#include
#include #include
#include
#include
#define MKFIFO_FILE"/tmp/sharefile"struct msg_struct{
char sex;
char name[32];
int age;
long weight;
//......................
};
int main()
{
int ret = mkfifo(MKFIFO_FILE,0666|O_CREAT);
if(ret<0){
if(errno == EEXIST){
printf("reader find file exist,do nothing\n");
}else {
perror("reader find err");
exit(-3);
}
}
int fd = open("/tmp/sharefile",O_RDWR);
if(fd<0){
perror("reader open err");
exit(0);
}
struct msg_struct readmsg;
while(1){
memset(&readmsg,0,sizeof(readmsg));
/*
如果管道fifo fd中,暂时没有数据,read会在函数内部阻塞等待数据
*/
ret = read(fd,&readmsg,sizeof(readmsg));
if(ret<0){
perror("reader read err");
return -34;
}
printf("reader got:len = %d name %s sex=%c age=%d weight=%ld\n",\
ret,readmsg.name,readmsg.sex,readmsg.age,readmsg.weight);
}
close(fd);
/*删除该文件*/
unlink("/tmp/sharefile");
}
2、共享内存
共享内存就是在内存中申请一片空间,可以让进程之间相互访问。这样就可以实现进程之间的相互通讯。
申请空间共同访问分为一下几步:
(1)、 创建/获取 共享内存,没有则创建,有则获取
int shmid = shmget(KEYS_SHM, sizeof( *ptshm),0666|IPC_CREAT);
if(shmid == -1){
perror("shmget err");
return -34;
}
【windows|嵌入式培训经验分享——进程之间的通讯(常用)】
int shmget( int keys,int shmsize, int mode )
#include
#include
int shmget(key_t key, size_t size, int shmflg);
key:共享内存 相关的一个keys, 双方可以通过该keys获取同一片空间
他是一个正数
size: 你要创建/获取 空间的大小
shmflg: 你想这次如何访问,r w
shmflg它是由32bit构成, 每个bit表示一种属性.
0666,如果shmflg没有IPC_CREAT,则只是获取系统中已存在的(keys)指定的那个间
如果shmflg,有IPC_CREAT, 如果空间已存在直接获取, 不存在则创建
返回值
一个共享空间的 id,以后通过该id访问这个内存.
-1:错误的,errno
(2)、地址映射
ptshm = shmat(shmid,NULL,0);
if(ptshm == (void*)-1){
perror("shmat err");
return 0;
}
映射共享空间,到本进程的某个地址,以后通过该地址访问该空间
#include
#include
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmaddr: 如果你想把shm映射到你指定的 地址,你传递该地址即可
如果NULL,系统会选择一个地址给你
shmflg:
SHM_RDONLY 只读访问
0读写
返回值:
成功一个可以访问shm的地址
失败(void *) -1is returned,
(3)、在申请空间访问结束之后,我们通常都需要释放该空间,释放该空间分为两步
断开连接:
int ret=shmdt(ptshm);
if(ret<0){
perror("shmdt err");
return 0;
}
释放空间:
ret = shmctl(shmid, IPC_RMID, NULL);
if(ret<0){
perror("shmctl err:");
return -3;
}
3、信号通讯(又称为软件中断)
#include
#include
#include
#include
/*
signo: 当前发生信号的 num
*/
void sig_intr_handle(int signo )
{
if(signo == SIGINT){
printf("I recv SIGINT signal\n");
//sleep(2);
//exit(0);
}else if(signo==SIGSEGV){
printf("I recv SIGSEGV signal\n");
}else if(signo == SIGUSR1){
printf("I recv SIGUSR1 signal\n");
}else if(signo==SIGUSR2){
printf("I recv SIGUSR2 signal\n");
exit(2);
}
} int main()
{
signal_handle,该信号的处理方法
*/
signal(SIGINT, sig_intr_handle);
signal(SIGSEGV,sig_intr_handle);
signal(SIGUSR1,sig_intr_handle);
signal(SIGUSR2,sig_intr_handle);
while(1){printf("main process\n");
sleep(3);
}
}
/*指定 当进程接收到某种信号的时候,的处理方法
#include
sighandler_t signal(int signum,void (*signal_handle)(int));
signum,你要处理的信号
1) SIGHUP2) SIGINT3) SIGQUIT4) SIGILL5) SIGTRAP
6) SIGABRT7) SIGBUS8) SIGFPE9) SIGKILL10) SIGUSR1
11) SIGSEGV12) SIGUSR213) SIGPIPE14) SIGALRM15) SIGTERM
16) SIGSTKFLT17) SIGCHLD18) SIGCONT19) SIGSTOP20) SIGTSTP
21) SIGTTIN22) SIGTTOU23) SIGURG24) SIGXCPU25) SIGXFSZ
26) SIGVTALRM27) SIGPROF28) SIGWINCH29) SIGIO30) SIGPWR
31) SIGSYS34) SIGRTMIN35) SIGRTMIN+136) SIGRTMIN+237) SIGRTMIN+3
38) SIGRTMIN+439) SIGRTMIN+540) SIGRTMIN+641) SIGRTMIN+742) SIGRTMIN+8
43) SIGRTMIN+944) SIGRTMIN+1045) SIGRTMIN+1146) SIGRTMIN+1247) SIGRTMIN+13
48) SIGRTMIN+1449) SIGRTMIN+1550) SIGRTMAX-1451) SIGRTMAX-1352) SIGRTMAX-12
53) SIGRTMAX-1154) SIGRTMAX-1055) SIGRTMAX-956) SIGRTMAX-857) SIGRTMAX-7
58) SIGRTMAX-659) SIGRTMAX-560) SIGRTMAX-461) SIGRTMAX-362) SIGRTMAX-2
63) SIGRTMAX-164) SIGRTMAX
通常我们也用不了这么多,就需要记住一些常用的就行了。
设定完成之后可以使用另一个进程发送信号:
#include
#include
#include
int main(int argc,char **argv)
{
int pid = atoi(argv[1]);
while(1){int ret = kill(pid, 2);
if(ret<0){
perror("kill int err");
return -3;
}
sleep(3);
ret = kill(pid, 10);
if(ret<0){
perror("kill int err");
return -3;
}
sleep(3);
}
}
推荐阅读
- 历史上的今天|【历史上的今天】8 月 24 日(Windows 95 问世;乔布斯辞任苹果 CEO;库克上台)
- 视频处理|用 C 语言编写的临近缩放算法
- 嵌入式开发|一款简单好用的日志系统
- Python|在Anaconda中用pip安装Pytorch后无法用pycharm打开
- 笔记|链表的基本操作(增删改查)--C语言
- visual|由于找不到vcruntime140_1.dll,无法继续执行代码重新安装程序可能会解决此问题。
- 【C语言】判断上三角矩阵
- WSL|win11显示文件后缀
- 笔记|weblogic 8.1 控制台密码丢失了怎么办