【linux草鞋应用编程系列】_3_ 进程间通信
一、进程间通信
PIPE() Linux Programmer’s Manual PIPE()
NAME
pipe - create pipe
SYNOPSIS
#include <unistd.h> int pipe(int filedes[]); //参数为一个长度为2 的整型数组的数组首地址, 为输出参数,
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h> int main(int argc,char* argv[])
{
int fd_pipe[];
pid_t pid;
char buf[]; //创建管道
if( pipe(fd_pipe) )
{
perror("create pipe");
exit();
} pid=fork();
if( ==pid )
{
/*close(fd_pipe[1]); //关闭写端*/
read(fd_pipe[], buf,sizeof(buf));
printf("in child process read data from pipe.\n");
printf("the data read from pipe is:%s\n",buf);
exit();
}
/*close(fd_pipe[0]); //关闭读端*/
write(fd_pipe[], "pipe test",sizeof("pipe test"));
sleep();
return ;
}
[root@localhost ipc]# gcc main.c
[root@localhost ipc]# ./a.out
in child process read data from pipe.
the data read from pipe is:pipe test
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h> #define CHAR "pipe test from child to parent\n" int main(int argc,char* argv[])
{
int fd_pipe[];
pid_t pid;
char buf[]; //创建管道
if( pipe(fd_pipe) )
{
perror("create pipe");
exit();
} pid=fork();
if( ==pid )
{
close(fd_pipe[]);
write(fd_pipe[],CHAR,sizeof(CHAR));
exit();
} close(fd_pipe[]);
read(fd_pipe[],buf,sizeof(buf));
printf("data from child is: %s",buf); return ;
}
[root@localhost ipc]# gcc main.c
[root@localhost ipc]# ./a.out
data from child is: pipe test from child to parent
MKFIFO() Linux Programmer’s Manual MKFIFO()
NAME
mkfifo - make a FIFO special file (a named pipe)
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h> int mkfifo( const char *pathname, //生成的管道特殊文件的位置和文件名
mode_t mode); //管道特殊文件的访问权限
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h> #define CHAR "pipe named\n" int main(int argc,char* argv[])
{
int fd;
int ret; //创建管道
ret=mkfifo("./fifo-pipe",);
if(ret)
{
perror("mkfifo: fifo-pipe");
exit();
} fd=open("./fifo-pipe",O_WRONLY);
write(fd,CHAR,sizeof(CHAR)); close(fd);
return ;
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> int main(int argc,char* argv[])
{
int fd;
int ret;
char buf[]; //打开命名管道文件
fd=open("./fifo-pipe",O_RDONLY);
if(- == fd)
{
perror("open fifo-pipe");
exit();
} ret=read(fd,buf,sizeof(buf));
if(ret<)
{
perror("read fifo-pipe");
exit();
}
printf("the data read from fifo pipe:%s\n",buf); close(fd);
return ;
}
[root@localhost pipe]# ll //查看没有 fifo-pipe 的命名管道文件
总计
-rw-r--r-- root root - : pipe_fork.c
-rw-r--r-- root root - : pipe-r.c
-rw-r--r-- root root - : pipe-w.c
-rwxr-xr-x root root - : rp
-rwxr-xr-x root root - : wp
[root@localhost pipe]# ./wp & //wp运行,并且进入后台
[]
[root@localhost pipe]# jobs
[]+ Running ./wp & //wp在后台运行, 等待命名管道的数据被读取, 即wp 阻塞
[root@localhost pipe]# ./rp //rp 读取管道数据,
the data read from fifo pipe:pipe named //数据读取成功 []+ Done ./wp //管道中的数据被读取完后,wp不再阻塞,返回
[root@localhost pipe]# jobs
[root@localhost pipe]# ll
总计
prw-r--r-- root root - : fifo-pipe //生成一个命名管道文件
-rw-r--r-- root root - : pipe_fork.c
-rw-r--r-- root root - : pipe-r.c
-rw-r--r-- root root - : pipe-w.c
-rwxr-xr-x root root - : rp
-rwxr-xr-x root root - : wp
[root@localhost pipe]#
FTOK() Linux Programmer’s Manual FTOK()
NAME
ftok - convert a pathname and a project identifier to a System V IPC key
//由一个特定的工程号和文件生成一个特定的IPC键值,
SYNOPSIS
# include <sys/types.h>
# include <sys/ipc.h> key_t ftok(const char *pathname, //文件名
int proj_id); //工程号
MSGGET() Linux Programmer’s Manual MSGGET()
NAME
msgget - get a message queue identifier SYNOPSIS
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h> int msgget( key_t key, //IPC 键值
int msgflg); //打开或者创建标志, 可以取值 IPC_CREAT
MSGOP() Linux Programmer’s Manual MSGOP()
NAME
msgop - message operations
SYNOPSIS
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h> int msgsnd(int msqid, //消息队列ID
const void *msgp, //要发送的消息的消息结构体
size_t msgsz, //消息字符串的大小,或者消息结构的大小
int msgflg); // 消息标志 ssize_t msgrcv(int msqid, //消息队列ID
void *msgp, //接受消息的消息结构体指针
size_t msgsz, //消息结构体的大小
long msgtyp, //指定要接收到消息的类型
int msgflg); //消息标志
要发送或接收消息,还需要定义一个如下格式的结构体:
struct msgbuf {
long mtype; /* message type, must be > 0 */ //消息类型, 这个值必须大于 0
char mtext[]; /* message data */ //要发送的消息数据, 字符数组长度可以根据实际需要定义
};
MSGCTL() Linux Programmer’s Manual MSGCTL()
NAME
msgctl - message control operations
SYNOPSIS
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h> int msgctl(int msqid, //消息队列ID
int cmd, //操作命令, 操作命令有很多,删除消息队列用 IPC_RMID 命令
struct msqid_ds *buf); //输出参数,通过这个结构体可获取消息队列的状态信息,如果不需要获取
//消息队列的信息,那么就设置为NULL
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h> typedef struct
{
long type;
char data[];
}msgbuf; int main(void)
{
int ret;
key_t key;
int msgid;
msgbuf msg={
type: ,
data: "this is a message queue test.\n",
}; //获取键值
key=ftok("./msgsnd.c",);
if(- == key)
{
perror("ftok");
exit();
} //打开或创建一个消息队列
msgid=msgget(key,IPC_CREAT);
if(- == msgid )
{
perror("msgget");
exit();
} //发送消息
ret=msgsnd(msgid,&msg,sizeof(msgbuf),);
if(- == ret)
{
perror("msgsnd");
} return ;
}
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h> typedef struct
{
long type;
char data[];
}msgbuf; int main(int argc,char* argv[])
{
int ret;
key_t key;
int msgid;
msgbuf msg; //获取键值
key=ftok("./msgsnd.c",);
if(- == key )
{
perror("ftok");
exit();
} //打开消息队列
msgid=msgget(key,);
if(- == msgid )
{
perror("msgget");
exit();
} //接收消息
ret=msgrcv(msgid, &msg, sizeof(msgbuf),,);
if(- == ret)
{
perror("msgrcv");
exit();
}
printf("the recive message is: %s",msg.data); //删除消息队列
msgctl(msgid,IPC_RMID,NULL); return ;
}
[root@localhost msg]# gcc msgsnd.c -o snd
[root@localhost msg]# gcc msgrcv.c -o rcv
[root@localhost msg]# ./snd
[root@localhost msg]# ./rcv
the recive message is: this is a message queue test.
[root@localhost msg]#
/* semop system calls takes an array of these. */
struct sembuf {
unsigned short sem_num; /* semaphore index in array */ //信号量集合中的信号量索引值,即表示信号量集合中第几个信号量
short sem_op; /* semaphore operation */ //要对信号量进行的操作,=-1 表示信号量不可获取, =1 表示可以获取信号量
short sem_flg; /* operation flags */ //信号量标志
};
SEMGET() Linux Programmer’s Manual SEMGET()
NAME
semget - get a semaphore set identifier //获取一个信号集合的ID SYNOPSIS
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h> int semget( key_t key, //IPC键值
int nsems, //信号量集合中信号量的个数, 要创建的信号量到个数
int semflg); //信号量的标志, 同OPEN的打开标志类似
SEMCTL() Linux Programmer’s Manual SEMCTL()
NAME
semctl - semaphore control operations SYNOPSIS
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h> int semctl(int semid, //信号量集合ID
int semnum, //信号量集合中的信号量索引值
int cmd, //要对信号量进行的操作,可以使用的命名: IPC_SET、IPC_STAT、IPC_INFO、GETVAL、SETVAL......
...); //最后一个参数根据 操作的不同,可以传递,也可以不传递
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) */
};
SEMOP() Linux Programmer’s Manual SEMOP() NAME
semop, semtimedop - semaphore operations SYNOPSIS
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h> int semop(int semid, //信号量集合ID
struct sembuf *sops, //信号量结构体指针
unsigned nsops); //表示要操作的信号量个数 int semtimedop(int semid, //信号量集合ID
struct sembuf *sops, //信号量结构体指针
unsigned nsops, //表示要操作的信号量个数
struct timespec *timeout); //表示超时等待时间,如果在超时时间内没有获取到可操作的信号量,就返回
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <fcntl.h>
#include <stdlib.h> int main(void)
{
int i;
int j;
int ret;
int fd;
pid_t pid;
key_t key;
int semid;
char buf[];
int size;
struct sembuf sembuf; /*sembuf=(struct sembuf*)malloc(sizeof (struct sembuf));*/
//打开文件,用来进行操作
fd=open("./test",O_RDWR | O_CREAT | O_TRUNC,);
if(- == fd)
{
perror("open");
exit();
} //IPC键值
key=ftok("./main.c",);
if(- == key)
{
perror("ftok");
exit();
} //获取信号量集合的ID
semid=semget(key,,IPC_CREAT);
if(- == semid )
{
perror("semget");
exit();
} //初始化信号量集合中的第一个信号量,设定信号量的值为0 , sem.sem_op = 0;
ret=semctl(semid, , SETVAL, ); pid=fork();
if( pid== )
//----------------子进程------------
{
//信号量的P 操作, 即加锁信号量
sembuf.sem_num=;
sembuf.sem_op=-;
sembuf.sem_flg=;
semop(semid,&sembuf,); size=sprintf(buf,"pid=%d, ppid=%d\n",getpid(),getppid());
for(i=;i<;i++)
{
j=;
while(j<size)
{
ret=write(fd,&buf[j++], );
if(- == ret)
{
perror("write");
exit();
}
usleep();
}
}
//信号量的V操作,即解锁信号量
sembuf.sem_num=;
sembuf.sem_op=;
sembuf.sem_flg=;
semop(semid,&sembuf,); exit();
}//---------------子进程结束--------------------- //-----------------------父进程---------------
//信号量的P 操作, 即加锁信号量
sembuf.sem_num=;
sembuf.sem_op=-;
sembuf.sem_flg=;
semop(semid,&sembuf,); size=sprintf(buf,"pid=%d, ppid=%d\n",getpid(),getppid());
for(i=;i<;i++)
{
j=;
while(j<size)
{
ret=write(fd,&buf[j++], );
if(- == ret)
{
perror("write");
exit();
}
usleep();
}
} //信号量的V操作,即解锁信号量
sembuf.sem_num=;
sembuf.sem_op=;
sembuf.sem_flg=;
semop(semid,&sembuf,); semctl(semid,,IPC_RMID);
close(fd); return ;
}
pid=, ppid=
pid=, ppid=
pid=, ppid=
pid=, ppid=
pid=, ppid=
pid=, ppid=
pid=, ppid=
pid=, ppid=
pid=, ppid=
pid=, ppid=
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <fcntl.h>
#include <stdlib.h> int main(void)
{
int i;
int j;
int ret;
int fd;
pid_t pid;
key_t key;
int semid;
char buf[];
int size;
struct sembuf sembuf; /*sembuf=(struct sembuf*)malloc(sizeof (struct sembuf));*/
//打开文件,用来进行操作
fd=open("./test",O_RDWR | O_CREAT | O_TRUNC,);
if(- == fd)
{
perror("open");
exit();
} //IPC键值
key=ftok("./main.c",);
if(- == key)
{
perror("ftok");
exit();
} //获取信号量集合的ID
semid=semget(key,,IPC_CREAT);
if(- == semid )
{
perror("semget");
exit();
} //初始化信号量集合中的第一个信号量,设定信号量的值为0
ret=semctl(semid, , SETVAL, ); pid=fork();
if( pid== )
//----------------子进程------------
{
//信号量的P 操作, 即加锁信号量
sembuf.sem_num=;
sembuf.sem_op=-;
sembuf.sem_flg=;
/*semop(semid,&sembuf,1);*/ //取消信号量到作用 size=sprintf(buf,"pid=%d, ppid=%d\n",getpid(),getppid());
for(i=;i<;i++)
{
j=;
while(j<size)
{
ret=write(fd,&buf[j++], );
if(- == ret)
{
perror("write");
exit();
}
usleep();
}
}
//信号量的V操作,即解锁信号量
sembuf.sem_num=;
sembuf.sem_op=;
sembuf.sem_flg=;
/*semop(semid,&sembuf,1);*/ //取消信号量到作用 exit();
}//---------------子进程结束--------------------- //-----------------------父进程---------------
//信号量的P 操作, 即加锁信号量
sembuf.sem_num=;
sembuf.sem_op=-;
sembuf.sem_flg=;
/*semop(semid,&sembuf,1);*/ //取消信号量到作用 size=sprintf(buf,"pid=%d, ppid=%d\n",getpid(),getppid());
for(i=;i<;i++)
{
j=;
while(j<size)
{
ret=write(fd,&buf[j++], );
if(- == ret)
{
perror("write");
exit();
}
usleep();
}
} //信号量的V操作,即解锁信号量
sembuf.sem_num=;
sembuf.sem_op=;
sembuf.sem_flg=;
/*semop(semid,&sembuf,1);*/ //取消信号量到作用 semctl(semid,,IPC_RMID);
close(fd); return ;
}
ppiidd==,, ppppiidd== ppiidd==,, ppppiidd==
7p
ipdi=d2=, ,p ppipdi=d7=
3p7i
dp=i2d3=, 8p,p ipdp=i7d1=
3p3i7d
=p2i3d3=, 3p8p,i dp=p7i1d4=
SHMGET() Linux Programmer’s Manual SHMGET()
NAME
shmget - allocates a shared memory segment
SYNOPSIS
#include <sys/ipc.h>
#include <sys/shm.h> int shmget(key_t key, //IPC 键值
size_t size, //要申请的内存空间的大小
int shmflg); //共享内存的空间打开标志 ,与 open 的打开标志类似,
返回值:
申请成功返回共享内存标识ID, 失败返回-。
SHMOP() Linux Programmer’s Manual SHMOP()
NAME
shmop - shared memory operations
SYNOPSIS
#include <sys/types.h>
#include <sys/shm.h> void *shmat(int shmid, //共享内存标志ID
const void *shmaddr, //传递NULL,表示要系统分配存储缓冲区,传递地址表示指定地址
int shmflg); //打开标志, int shmdt(const void *shmaddr); //删除共享内存
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <string.h> #define SHM_SIZE 128 int main(int argc,char* argv[])
{
key_t key;
int shm_id;
char* shm_p; //获取IPC 键值
key=ftok("./shm-w.c",);
if(- == key)
{
perror("ftok");
exit();
} //申请共享内存空间,大小为 SHM_SIZE
shm_id=shmget(key,SHM_SIZE,IPC_CREAT);
if(- == shm_id )
{
perror("shmget");
exit();
} //将申请的共享内存映射到用户空间
shm_p=shmat(shm_id,NULL,); //
if(NULL == shm_p )
{
perror("shmat");
exit();
} //将数据写入到共享内存 写入到数据可以在其他进程中读取
memset(shm_p,,SHM_SIZE);
strcpy(shm_p, "this is a sheard memmory.\n"); //这个函数不安全,需要注意 return ;
} 从共享内存中读取数据的文件 shm-r.c
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <string.h> #define SHM_SIZE 128 int main(int argc,char* argv[])
{
key_t key;
int shm_id;
char* shm_p;
char buf[SHM_SIZE]; //获取IPC 键值
key=ftok("./shm-w.c",);
if(- == key)
{
perror("ftok");
exit();
} //申请共享内存空间,大小为 SHM_SIZE
shm_id=shmget(key,SHM_SIZE,IPC_CREAT);
if(- == shm_id )
{
perror("shmget");
exit();
} //将申请的共享内存映射到用户空间
shm_p=shmat(shm_id,NULL,); //
if(NULL == shm_p )
{
perror("shmat");
exit();
} //从共享内存读取数据
memset(buf,,SHM_SIZE);
strcpy(buf, shm_p); //这个函数不安全,需要注意
printf("the data read from sheard memory is: %s",buf); shmdt(shm_p); //申请撤销共享内存
return ;
}
[root@localhost shm]# gcc shm-w.c -o shmw
[root@localhost shm]# gcc shm-r.c -o shmr
[root@localhost shm]# ./shmw
[root@localhost shm]# ./shmr
the data read from sheard memory is: this is a sheard memmory.
[root@localhost shm]#
【Linux草鞋应用编程系列】_3_进程间通信
本系列文章未完,待续。
如果查看的过程中发现错误,请不吝指教,包括错别字、标点符号等。
【linux草鞋应用编程系列】_3_ 进程间通信的更多相关文章
- 【linux草鞋应用编程系列】_4_ 应用程序多线程
一.应用程序多线程 当一个计算机上具有多个CPU核心的时候,每个CPU核心都可以执行代码,此时如果使用单线程,那么这个线程只能在一个 CPU上运行,那么其他的CPU核心就处于空闲状态,浪费了系 ...
- 【linux草鞋应用编程系列】_1_ 开篇_系统调用IO接口与标准IO接口
最近学习linux系统下的应用编程,参考书籍是那本称为神书的<Unix环境高级编程>,个人感觉神书不是写给草鞋看的,而是 写给大神看的,如果没有一定的基础那么看这本书可能会感到有些头重脚轻 ...
- 【linux草鞋应用编程系列】_6_ 重定向和VT100编程
一.文件重定向 我们知道在linux shell 编程的时候,可以使用文件重定向功能,如下所示: [root@localhost pipe]# echo "hello world&q ...
- 【linux草鞋应用编程系列】_5_ Linux网络编程
一.网络通信简介 第一部分内容,暂时没法描述,内容实在太多,待后续专门的系列文章. 二.linux网络通信 在linux中继承了Unix下“一切皆文件”的思想, 在linux中要实现网 ...
- 【linux草鞋应用编程系列】_2_ 环境变量和进程控制
一. 环境变量 应用程序在执行的时候,可能需要获取系统的环境变量,从而执行一些相应的操作. 在linux中有两种方法获取环境变量,分述如下. 1.通过main函数的参数获取环境变量 ...
- Linux C++ 网络编程学习系列(1)——端口复用实现
Linux C++ 网络编程学习系列(1)--端口复用实现 源码地址:https://github.com/whuwzp/linuxc/tree/master/portreuse 源码说明: serv ...
- 《Linux/Unix系统编程手册》读书笔记3
<Linux/Unix系统编程手册>读书笔记 目录 第6章 这章讲进程.虚拟内存和环境变量等. 进程是一个可执行程序的实例.一个程序可以创建很多进程. 进程是由内核定义的抽象实体,内核为此 ...
- Linux下的编程实战【转】
一篇比较不错的文章, 降到了 makefile make , gcc编译器,GDB调试器, Linux文件系统,Linux文件API,.C语言库函数(C库函数的文件操作实际上是独立于具体的操作系统平台 ...
- Linux 高性能服务器编程——多进程编程
问题聚焦: 进程是Linux操作系统环境的基础. 本篇讨论以下几个内容,同时也是面试经常被问到的一些问题: 1 复制进程映像的fork系统调用和替换进程映像的exec系列系统调 ...
随机推荐
- MySQL 启动服务报错解决方案
标签:ERROR! The server quit without updating PID file (/var/lib/mysql/localhost.localdomain.pid) 概述 文章 ...
- 辛巴学院-Unity-剑英陪你零基础学c#系列(四)函数和封装
辛巴学院:正大光明的不务正业. 国庆长假结束了,我的心情是这样的: 你总是起不早,起不早独自一个人沉睡到天亮你无怨无悔的梦着那副本我知道你根本就不想上班你总是起不早,起不早放假总是短暂,上班太难请个病 ...
- springboot之HelloWorld
简介 为了简化开发Spring的复杂度,Spring提供了SpringBoot可以快速开发一个应用,这里就简单介绍下SpringBoot如何快速开发一个J2EE应用 HelloWorld 首先在gra ...
- 【原】Python用例:将指定文件或目录打包成zip文件
#This Demo is used to compress files to .zip file #Base on Windows import os import time #The files ...
- 单独使用jdbc编程问题总结(一)
在学习Mybatis之前,我们先来回顾JDBC编程的相关知识.在此基础上深入的学习Mybatis框架.如有错误,敬请指正. (一)首先我们既然要使用jdbc,当然是要操作数据库了.创建一个名为:myb ...
- 【PRINCE2是什么】PRINCE2认证之七大原则(3)
我们先来回顾一下,PRINCE2七大原则分别是持续的业务验证,经验学习,角色与责任,按阶段管理,例外管理,关注产品,剪裁. 第三个原则:明确定义的角色和职责. 项目离不开人员,错误的人来了,合适的人没 ...
- Android开发学习之路-二维码学习
这个月装逼有点少了,为什么呢,因为去考软件射鸡师了,快到儿童节了,赶紧写篇博纪念一下逝去的青春,唔,请忽略这句话. 二维码其实有很多种,但是我们常见的微信使用的是一种叫做QRCode的二维码,像下面这 ...
- MonogDB初探增加和删除
1.插入并保存文档 在插入数据之前,首先用mongodb Shell命令db.baseUser.find() 查找集合的数据. 想必大家能猜到结果,什么东西都没有,那接着来说说怎 ...
- Java 的设计模式之一装饰者模式
刚开始接触装饰者的设计模式,感觉挺难理解的,不够后来花了一个晚上的时间,终于有头绪了 装饰者设计模式:如果想对已经存在的对象进行装饰,那么就定义一个类,在类中对已经有的对象进行功能的增强或添加另外的行 ...
- Spill data to tempdb
查看Execution Plan时,在Sort Operator上,发现一个Warning:Operator used tempdb to spill data during execution wi ...