Linux进程间通信(一)——管道、信号量 .
2013-03-27 11:24
399 查看
一、Linux进程间通信方式 :有六种方式在两个程序间传递信息
1、信号( Singal )
2、管道 ( Pipe ) 及有名管道
3、信号量 ( Semaphore )
4、共享内存 ( SharedMessage)
5、消息队列 ( MessageQueue )
6、套接字 ( Socket )
其中,共享内存是效率最高的。
二、具体介绍
1、信号( Singal ) 可以参考
linux多进程——进程组与会话、守护进程、信号通信 中的信号通信部分
2、管道 ( Pipe ) 及有名管道
管道分为有名和无名管道。
无名管道用于父子进程间的通信。
a、用pipe( )创建无名管道
[cpp]
view plaincopyprint?
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<memory.h>
#include<signal.h>
void my_func(int);
int main(){
pid_t pid;
int pfd[2];
char *msg="pipe test program";
char buf[100];
int r,w;
memset(buf,0,sizeof(buf));
//创建一个无名管道。一定要在fork之前创建。这样子进程才能有同样的一个管道
if(pipe(pfd)<0){
printf("pipe create error!\n");
exit(1);
}
if((pid = fork())<0){
printf("fork error!\n");
exit(1);
}else if(pid == 0){
//close(pfd[0]); //此句是测试异常的时候使用
close(pfd[1]);
sleep(3);
if(r=read(pfd[0],buf,100)<0){
printf("read error!\n");
waitpid(pid,NULL,0); //等待子进程退出后再退出
exit(1);
}else
printf("child read from pipe: %s\n",buf);
close(pfd[0]);
}else{
signal(SIGPIPE,my_func); //当读端不存在时系统发出SIGPIPE信号
close(pfd[0]);
sleep(1);
if(w=write(pfd[1],msg,strlen(msg))<0){
printf("wirte error!\n");
exit(1);
}else
printf("parent send msg to child!\n");
close(pfd[1]);
waitpid(pid,NULL,0);
}
return 0;
}
void my_func(int sig){
if(sig == SIGPIPE){
printf("read not exist\n");
}
}
b、标准流管道: popen()
这个函数会完成:创建管道、fork()、关闭相应的文件描述符、执行exec、执行函数中指定的命令 这一系列的操作。优点当然是省事啦,缺点必然是不灵活。popen( )返回的是文件指针所以要用标准IO操作。其中,第二个参数:"
r " 表示命令的输出作为程序的输入;" w " 表示程序的输出作为命令的输入。另外要注意用pclose( ) 关闭文件流。两个函数出错
[cpp]
view plaincopyprint?
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<memory.h>
#include<signal.h>
int main(){
FILE *fp;
int pfd[2];
char *cmd="ls -l";
char buf[100];
if((fp=popen(cmd,"r")) == NULL){
printf("popen error\n");
exit(1);
}
while(fgets(buf,100,fp)!= NULL){
printf("from fp:%s",buf);
}
pclose(fp);
return 0;
}
c、有名管道FIFO
读数据的程序:
[cpp]
view plaincopyprint?
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<memory.h>
#include<errno.h>
#include<stdlib.h>
#define FIFO "pipetest"
int main(int argc,char* argv[]){
int fd,r;
char buff[1024];
if(access(FIFO,F_OK)==-1){ //判断管道是否存在,管道是不可以重复创建的
if(mkfifo(FIFO,0666)<0){
if(errno==EEXIST)
printf("it already exist\n");
printf("create fifo error! it already exist\n");
exit(1);
}
}
if((fd=open("in1",O_RDONLY))<0){
printf("open in1 error!\n");
return 1;
}
while(1){
memset(buff,0,1024);
if(r=read(fd,buff,1024)>0){
printf("send to name pipe: %s\n",buff);
}
}
close(fd);
}
写数据的程序:
[cpp]
view plaincopyprint?
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<memory.h>
#include<errno.h>
#include<stdlib.h>
#define FIFO "pipetest"
int main(int argc,char* argv[]){
int fd,w;
char buff[1024];
if(argc<2){
printf("Usage: ./%s <string>\n",argv[0]);
exit(0);
}
sscanf(argv[1],"%s",buff);
if(access(FIFO,F_OK)==-1){
if(mkfifo(FIFO,0666)<0){
if(errno==EEXIST)
printf("it already exist\n");
printf("create fifo error!\n");
exit(1);
}
}
if((fd=open("in1",O_WRONLY))<0){
printf("open in1 error!\n");
return 1;
}
if(w=write(fd,buff,1024)>0){
printf("send to name pipe: %s\n",buff);
}
close(fd);
}
3、信号量
信号量和信号通信( Signal )可不一样。信号量( Semaphore ) 是用于解决不同程序间的访问问题。即同步和互斥。
同步是指多线程程序按照一定的顺序执行一段完整的代码。互斥指多线程程序访问同一个变量时只能有一个线程在访问。
信号量就是为了解决同步和互斥的IPC机制,信号量为0则没有资源,进程进入等待队列,直到资源被释放为止。
信号量编程的步骤:
1、创建信号量或获得在系统中已经存在的信号量
调用semget () 函数 。使用同一个信号量键值即可获得同一个信号量。
2、初始化信号量
使用semctl( ) 函数的SETVAL。当使用二维信号量时,初始化为1。
3、进行信号量的PV操作
调用semop( ) 。实现同步与互斥。
4、不需要信号量则从系统中删除
使用semclt( ) 函数的IPC_RMID 。
一个操作方法的封装函数文件:
[cpp]
view plaincopyprint?
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<memory.h>
#include<errno.h>
#include<stdlib.h>
#define FIFO "pipetest"
int main(int argc,char* argv[]){
int fd,w;
char buff[1024];
if(argc<2){
printf("Usage: ./%s <string>\n",argv[0]);
exit(0);
}
sscanf(argv[1],"%s",buff);
if(access(FIFO,F_OK)==-1){
if(mkfifo(FIFO,0666)<0){
if(errno==EEXIST)
printf("it already exist\n");
printf("create fifo error! it already exist\n");
exit(1);
}
}
if((fd=open("in1",O_WRONLY))<0){
printf("open in1 error!\n");
return 1;
}
if(w=write(fd,buff,1024)>0){
printf("send to name pipe: %s\n",buff);
}
close(fd);
}
调用的例子:
[cpp]
view plaincopyprint?
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include"semcom.c"
int main(){
pid_t pid;
int semid;
if((semid=semget(ftok(".",'a'),1,0666|IPC_CREAT))<0){ //创建信号量
printf("semget error!\n");
exit(1);
}
init_sem(semid,1);
if((pid = fork())<0){
printf("fork error!\n");
exit(1);
}else if(pid == 0){
sem_p(semid); //在未释放之前父进程无法访问
printf("child is running......\n");
sleep(3);
printf("son is %d wake\n",getpid());
sem_v(semid);
}else{
sem_p(semid);
printf("parent is running......\n");
sleep(3);
printf("parent is %d wake\n",getpid());
sem_v(semid);
sleep(6);
del_sem(semid);
}
return 0;
}
1、信号( Singal )
2、管道 ( Pipe ) 及有名管道
3、信号量 ( Semaphore )
4、共享内存 ( SharedMessage)
5、消息队列 ( MessageQueue )
6、套接字 ( Socket )
其中,共享内存是效率最高的。
二、具体介绍
1、信号( Singal ) 可以参考
linux多进程——进程组与会话、守护进程、信号通信 中的信号通信部分
2、管道 ( Pipe ) 及有名管道
管道分为有名和无名管道。
无名管道用于父子进程间的通信。
a、用pipe( )创建无名管道
[cpp]
view plaincopyprint?
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<memory.h>
#include<signal.h>
void my_func(int);
int main(){
pid_t pid;
int pfd[2];
char *msg="pipe test program";
char buf[100];
int r,w;
memset(buf,0,sizeof(buf));
//创建一个无名管道。一定要在fork之前创建。这样子进程才能有同样的一个管道
if(pipe(pfd)<0){
printf("pipe create error!\n");
exit(1);
}
if((pid = fork())<0){
printf("fork error!\n");
exit(1);
}else if(pid == 0){
//close(pfd[0]); //此句是测试异常的时候使用
close(pfd[1]);
sleep(3);
if(r=read(pfd[0],buf,100)<0){
printf("read error!\n");
waitpid(pid,NULL,0); //等待子进程退出后再退出
exit(1);
}else
printf("child read from pipe: %s\n",buf);
close(pfd[0]);
}else{
signal(SIGPIPE,my_func); //当读端不存在时系统发出SIGPIPE信号
close(pfd[0]);
sleep(1);
if(w=write(pfd[1],msg,strlen(msg))<0){
printf("wirte error!\n");
exit(1);
}else
printf("parent send msg to child!\n");
close(pfd[1]);
waitpid(pid,NULL,0);
}
return 0;
}
void my_func(int sig){
if(sig == SIGPIPE){
printf("read not exist\n");
}
}
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<memory.h> #include<signal.h> void my_func(int); int main(){ pid_t pid; int pfd[2]; char *msg="pipe test program"; char buf[100]; int r,w; memset(buf,0,sizeof(buf)); //创建一个无名管道。一定要在fork之前创建。这样子进程才能有同样的一个管道 if(pipe(pfd)<0){ printf("pipe create error!\n"); exit(1); } if((pid = fork())<0){ printf("fork error!\n"); exit(1); }else if(pid == 0){ //close(pfd[0]); //此句是测试异常的时候使用 close(pfd[1]); sleep(3); if(r=read(pfd[0],buf,100)<0){ printf("read error!\n"); waitpid(pid,NULL,0); //等待子进程退出后再退出 exit(1); }else printf("child read from pipe: %s\n",buf); close(pfd[0]); }else{ signal(SIGPIPE,my_func); //当读端不存在时系统发出SIGPIPE信号 close(pfd[0]); sleep(1); if(w=write(pfd[1],msg,strlen(msg))<0){ printf("wirte error!\n"); exit(1); }else printf("parent send msg to child!\n"); close(pfd[1]); waitpid(pid,NULL,0); } return 0; } void my_func(int sig){ if(sig == SIGPIPE){ printf("read not exist\n"); } }
b、标准流管道: popen()
这个函数会完成:创建管道、fork()、关闭相应的文件描述符、执行exec、执行函数中指定的命令 这一系列的操作。优点当然是省事啦,缺点必然是不灵活。popen( )返回的是文件指针所以要用标准IO操作。其中,第二个参数:"
r " 表示命令的输出作为程序的输入;" w " 表示程序的输出作为命令的输入。另外要注意用pclose( ) 关闭文件流。两个函数出错
[cpp]
view plaincopyprint?
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<memory.h>
#include<signal.h>
int main(){
FILE *fp;
int pfd[2];
char *cmd="ls -l";
char buf[100];
if((fp=popen(cmd,"r")) == NULL){
printf("popen error\n");
exit(1);
}
while(fgets(buf,100,fp)!= NULL){
printf("from fp:%s",buf);
}
pclose(fp);
return 0;
}
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<memory.h> #include<signal.h> int main(){ FILE *fp; int pfd[2]; char *cmd="ls -l"; char buf[100]; if((fp=popen(cmd,"r")) == NULL){ printf("popen error\n"); exit(1); } while(fgets(buf,100,fp)!= NULL){ printf("from fp:%s",buf); } pclose(fp); return 0; }
c、有名管道FIFO
读数据的程序:
[cpp]
view plaincopyprint?
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<memory.h>
#include<errno.h>
#include<stdlib.h>
#define FIFO "pipetest"
int main(int argc,char* argv[]){
int fd,r;
char buff[1024];
if(access(FIFO,F_OK)==-1){ //判断管道是否存在,管道是不可以重复创建的
if(mkfifo(FIFO,0666)<0){
if(errno==EEXIST)
printf("it already exist\n");
printf("create fifo error! it already exist\n");
exit(1);
}
}
if((fd=open("in1",O_RDONLY))<0){
printf("open in1 error!\n");
return 1;
}
while(1){
memset(buff,0,1024);
if(r=read(fd,buff,1024)>0){
printf("send to name pipe: %s\n",buff);
}
}
close(fd);
}
#include<stdio.h> #include<fcntl.h> #include<unistd.h> #include<memory.h> #include<errno.h> #include<stdlib.h> #define FIFO "pipetest" int main(int argc,char* argv[]){ int fd,r; char buff[1024]; if(access(FIFO,F_OK)==-1){ //判断管道是否存在,管道是不可以重复创建的 if(mkfifo(FIFO,0666)<0){ if(errno==EEXIST) printf("it already exist\n"); printf("create fifo error! it already exist\n"); exit(1); } } if((fd=open("in1",O_RDONLY))<0){ printf("open in1 error!\n"); return 1; } while(1){ memset(buff,0,1024); if(r=read(fd,buff,1024)>0){ printf("send to name pipe: %s\n",buff); } } close(fd); }
写数据的程序:
[cpp]
view plaincopyprint?
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<memory.h>
#include<errno.h>
#include<stdlib.h>
#define FIFO "pipetest"
int main(int argc,char* argv[]){
int fd,w;
char buff[1024];
if(argc<2){
printf("Usage: ./%s <string>\n",argv[0]);
exit(0);
}
sscanf(argv[1],"%s",buff);
if(access(FIFO,F_OK)==-1){
if(mkfifo(FIFO,0666)<0){
if(errno==EEXIST)
printf("it already exist\n");
printf("create fifo error!\n");
exit(1);
}
}
if((fd=open("in1",O_WRONLY))<0){
printf("open in1 error!\n");
return 1;
}
if(w=write(fd,buff,1024)>0){
printf("send to name pipe: %s\n",buff);
}
close(fd);
}
#include<stdio.h> #include<fcntl.h> #include<unistd.h> #include<memory.h> #include<errno.h> #include<stdlib.h> #define FIFO "pipetest" int main(int argc,char* argv[]){ int fd,w; char buff[1024]; if(argc<2){ printf("Usage: ./%s <string>\n",argv[0]); exit(0); } sscanf(argv[1],"%s",buff); if(access(FIFO,F_OK)==-1){ if(mkfifo(FIFO,0666)<0){ if(errno==EEXIST) printf("it already exist\n"); printf("create fifo error!\n"); exit(1); } } if((fd=open("in1",O_WRONLY))<0){ printf("open in1 error!\n"); return 1; } if(w=write(fd,buff,1024)>0){ printf("send to name pipe: %s\n",buff); } close(fd); }
3、信号量
信号量和信号通信( Signal )可不一样。信号量( Semaphore ) 是用于解决不同程序间的访问问题。即同步和互斥。
同步是指多线程程序按照一定的顺序执行一段完整的代码。互斥指多线程程序访问同一个变量时只能有一个线程在访问。
信号量就是为了解决同步和互斥的IPC机制,信号量为0则没有资源,进程进入等待队列,直到资源被释放为止。
信号量编程的步骤:
1、创建信号量或获得在系统中已经存在的信号量
调用semget () 函数 。使用同一个信号量键值即可获得同一个信号量。
2、初始化信号量
使用semctl( ) 函数的SETVAL。当使用二维信号量时,初始化为1。
3、进行信号量的PV操作
调用semop( ) 。实现同步与互斥。
4、不需要信号量则从系统中删除
使用semclt( ) 函数的IPC_RMID 。
一个操作方法的封装函数文件:
[cpp]
view plaincopyprint?
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<memory.h>
#include<errno.h>
#include<stdlib.h>
#define FIFO "pipetest"
int main(int argc,char* argv[]){
int fd,w;
char buff[1024];
if(argc<2){
printf("Usage: ./%s <string>\n",argv[0]);
exit(0);
}
sscanf(argv[1],"%s",buff);
if(access(FIFO,F_OK)==-1){
if(mkfifo(FIFO,0666)<0){
if(errno==EEXIST)
printf("it already exist\n");
printf("create fifo error! it already exist\n");
exit(1);
}
}
if((fd=open("in1",O_WRONLY))<0){
printf("open in1 error!\n");
return 1;
}
if(w=write(fd,buff,1024)>0){
printf("send to name pipe: %s\n",buff);
}
close(fd);
}
#include<stdio.h> #include<fcntl.h> #include<unistd.h> #include<memory.h> #include<errno.h> #include<stdlib.h> #define FIFO "pipetest" int main(int argc,char* argv[]){ int fd,w; char buff[1024]; if(argc<2){ printf("Usage: ./%s <string>\n",argv[0]); exit(0); } sscanf(argv[1],"%s",buff); if(access(FIFO,F_OK)==-1){ if(mkfifo(FIFO,0666)<0){ if(errno==EEXIST) printf("it already exist\n"); printf("create fifo error! it already exist\n"); exit(1); } } if((fd=open("in1",O_WRONLY))<0){ printf("open in1 error!\n"); return 1; } if(w=write(fd,buff,1024)>0){ printf("send to name pipe: %s\n",buff); } close(fd); }
调用的例子:
[cpp]
view plaincopyprint?
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include"semcom.c"
int main(){
pid_t pid;
int semid;
if((semid=semget(ftok(".",'a'),1,0666|IPC_CREAT))<0){ //创建信号量
printf("semget error!\n");
exit(1);
}
init_sem(semid,1);
if((pid = fork())<0){
printf("fork error!\n");
exit(1);
}else if(pid == 0){
sem_p(semid); //在未释放之前父进程无法访问
printf("child is running......\n");
sleep(3);
printf("son is %d wake\n",getpid());
sem_v(semid);
}else{
sem_p(semid);
printf("parent is running......\n");
sleep(3);
printf("parent is %d wake\n",getpid());
sem_v(semid);
sleep(6);
del_sem(semid);
}
return 0;
}
相关文章推荐
- Linux进程间通信(一)——管道、信号量
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- Linux进程间通信--信号,管道,消息队列,信号量,共享内存,socket
- 【linux开发】进程间通信命名管道-共享内存-内存映射-消息队列-信号量
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- Linux进程间通信--信号,管道,消息队列,信号量,共享内存,socket
- Linux进程间通信--信号,管道,消息队列,信号量,共享内存,socket
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- Linux下进程间通信方式之管道、信号、共享内存、消息队列、信号量、套接字
- Linux进程间通信(一)——管道、信号量
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- Linux进程间通信方式--信号,管道,消息队列,信号量,共享内存
- Linux进程间通信--信号,管道,消息队列,信号量,共享内存,socket
- Linux进程间通信:管道,信号量,消息队列,信号,共享内存,套接字
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- Linux进程间通信:管道,信号量,消息队列,信号,共享内存,套接字