案例1:使用pipe()实现父子进程间通信,要求父进程作为写端,子进程作为读端。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
int fd[2];//定义文件描述符数组
int ret=pipe(fd);//创建管道
if(ret==-1)
{
perror("pipe");
exit(1);
}
pid_t pid=fork();
if(pid>0)
{
close(fd[0]);
char *p="hello,pipe\n";
write(fd[1],p,strlen(p)+1);
close(fd[1]);
wait(NULL);
}
else if(pid==0)
{
close(fd[1]);
char buf[64]={0};
ret=read(fd[0],buf,sizeof(buf));
close(fd[0]);
write(STDOUT_FILENO,buf,ret);
}
return 0;
}
案例2:使用管道实现兄弟进程间通信,使兄弟进程实现命令“ls | wc –l”的功能。在实现本案例时会用到重定向函数dup2(),该函数存在于函数库unistd.h中,函数声明如下:
int dup2(int oldfd, int newfd);
其功能是将参数oldfd的文件描述符复制给newfd,若函数调用成功则返回newfd,否则返回-1,并设置errno。
案例实现如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int fd[2];
int ret=pipe(fd);
if(ret==-1){
perror("pipe err");
exit(1);
}
int i;
pid_t pid,wpid;
for(i=0;i<2;i++){ //创建两个子进程
if((pid=fork())==0)
break;
}
if(2==i){ //父进程
close(fd[0]);
close(fd[1]);
wpid=wait(NULL);
printf("wait child 1 success,pid=%d\n",wpid);
pid=wait(NULL);
printf("wait child 2 success,pid=%d\n",pid);
}
else if(i==0){ //子进程—写
close(fd[0]);
dup2(fd[1],STDOUT_FILENO); //将fd[1]所指文件内容定向到标准输出
execlp("ls","ls",NULL);
}
else if(i==1){ //子进程—读
close(fd[1]);
dup2(fd[0],STDIN_FILENO);
execlp("wc","wc","-l",NULL);
}
return 0;
}
案例3:使用popen()函数与pclose()函数实现管道通信。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
FILE *r_fp,*w_fp;
char buf[100];
r_fp=popen("ls","r"); //读取命令执行结果
w_fp=popen("wc -l","w"); //将管道中的数据传递给进程
while(fgets(buf,sizeof(buf),r_fp)!=NULL)
fputs(buf,w_fp);
pclose(r_fp);
pclose(w_fp);
return 0;
}
案例4:使用FIFO实现没有亲缘关系进程间的通信。由于是没有亲缘关系的进程间通信,因此需要在两段程序中实现,
这里在程序fifo_write.c中实现FIFO的写操作,在程序fifo_read.c中实现FIFO的读操作。案例实现如下:
fifo_write.c //写
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8int main(int argc,char *argv[])
9{
10 if(argc<2) //判断是否传入文件名
11 {
12 printf("./a.out fifoname\n");
13 exit(1);
14 }
15 int ret = access(argv[1],F_OK); //判断fifo文件是否存在
16 if(ret==-1) //若fifo不存在就创建fifo
17 {
18 int r = mkfifo(argv[1],0664);
19 if(r==-1){ //判断文件是否创建成功
20 perror("mkfifo");
21 exit(1);
22 }
23 else{
24 printf("fifo creat success!\n");
25 }
26 }
27 int fd=open(argv[1],O_WRONLY); //以读写的方式打开文件
28 while(1){ //循环写入数据
29 char *p="hello,world!";
30 write(fd,p,strlen(p)+1);
31 sleep(1);
32 }
33 close(fd);
34 return 0;
35}
fifo_read.c //读
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8int main(int argc,char *argv[])
9{
10 if(argc<2) //判断是否传入文件名
11 {
12 printf("./a.out fifoname\n");
13 exit(1);
14 }
15 int ret = access(argv[1],F_OK); //判断文件是否存在
16 if(ret==-1) //若文件不存在则创建文件
17 {
18 int r = mkfifo(argv[1],0664);
19 if(r==-1){
20 perror("mkfifo");
21 exit(1);
22 }
23 else{
24 printf("fifo creat success!\n");
25 }
26 }
27 int fd = open(argv[1],O_RDONLY); //打开文件
28 if(fd==-1){
29 perror("open");
30 exit(1);
31 }
32 while(1){ //不断读取fifo中的数据并打印
33 char buf[1024]={0};
34 read(fd,buf,sizeof(buf));
35 printf("buf=%s\n",buf);
36 }
37 close(fd); //关闭文件
38 return 0;
39}
案例5:使用消息队列实现不同进程间的通信。因为要实现不同进程间的通信,所以此处使用两个程序msgsend.c、msgrcv.c分别作为消息的发送端和接收端。案例实现如下:
msgsend.c //发送端
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <string.h>
#define MAX_TEXT 512
struct my_msg_st{
long int my_msg_type;
char anytext[MAX_TEXT];
};
int main()
{
int idx=1;
int msgid;
struct my_msg_st data;
char buf[BUFSIZ];
msgid=msgget((key_t)1000,0664|IPC_CREAT);
if(msgid==-1){
perror("msgget err");
exit(-1);
}
while(idx<5){
printf("enter some text:");
fgets(buf,BUFSIZ,stdin);
data.my_msg_type=rand()%3+1;
strcpy(data.anytext,buf);
if(msgsnd(msgid,(void*)&data,sizeof(data),0)==-1){
perror("msgsnd err");
exit(-1);
}
idx++;
}
return 0;
}
msgrcv.c //接收端
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#define MAX_TEXT 512
struct my_msg_st{
long int my_msg_type;
char anytext[MAX_TEXT];
};
int main()
{
int idx=1;
int msgid;
struct my_msg_st data;
long int msg_to_rcv=0;
msgid=msgget((key_t)1000,0664|IPC_CREAT);
if(msgid==-1){
perror("msgget err");
exit(-1);
}
while(idx<5){
if(msgrcv(msgid,(void*)&data,BUFSIZ,msg_to_rcv,0)==-1){
perror("msgrcv err");
exit(-1);
}
printf("msg type:%ld\n",data.my_msg_type);
printf("msg content is:%s",data.anytext);
idx++;
}
if(msgctl(msgid,IPC_RMID,0)==-1){
perror("msgctl err");
exit(-1);
}
exit(0);
}
案例6:使用信号量实现父子进程同步,防止父子进程抢夺cpu。案例实现如下:
```javascript
1#include <stdio.h>
2#include <stdlib.h>
3#include <sys/sem.h>
4//自定义共用体
5union semu{
6 int val;
7 struct semid_ds* buf;
8 unsigned short* array;
9 struct seminfo* _buf;
10};
11static int sem_id;
12//设置信号量值
13static int set_semvalue()
14{
15 union semu sem_union;
16 sem_union.val=1;
17 if(semctl(sem_id,0,SETVAL,sem_union)==-1)
18 return 0;
19 return 1;
20}
21//p操作,获取信号量
22static int semaphore_p()
23{
24 struct sembuf sem_b;
25 sem_b.sem_num = 0;
26 sem_b.sem_op = -1;
27 sem_b.sem_flg = SEM_UNDO;
28 if(semop(sem_id,&sem_b,1)==-1){
29 perror("sem_p err");
30 return 0;
31 }
32 return 1;
33}
34//V操作,释放信号量
35static int semaphore_v()
36{
37 struct sembuf sem_b;
38 sem_b.sem_num=0;
39 sem_b.sem_op=1;
40 sem_b.sem_flg=SEM_UNDO;
41 if(semop(sem_id,&sem_b,1)==-1){
42 perror("sem_v err");
43 return 0;
44 }
45 return 1;
46}
47//删除信号量
48static void del_semvalue()
49{
50 union semu sem_union;
51 if(semctl(sem_id,0,IPC_RMID,sem_union)==-1)
52 perror("del err");
53}
54int main()
55{
56 int i;
57 pid_t pid;
58 char ch='C';
59 sem_id=semget((key_t)1000,1,0664|IPC_CREAT);//创建信号量
60 if(sem_id==-1){
61 perror("sem_c err");
62 exit(-1);
63 }
64 if(!set_semvalue()){ //设置信号量值
65 perror("init err");
66 exit(-1);
67 }
68 pid=fork(); //创建子进程
69 if(pid==-1){ //若创建失败
70 del_semvalue(); //删除信号量
71 exit(-1);
72 }
73 else if(pid==0) //设置子进程打印的字符
74 ch='Z';
75 else //设置父进程打印的字符
76 ch='C';
77 srand((unsigned int)getpid()); //设置随机数种子
78 for(i=0;i<8;i++) //循环打印字符
79 {
80 semaphore_p(); //获取信号量
81 printf("%c",ch);
82 fflush(stdout); //将字符打印到屏幕
83 sleep(rand()%4); //沉睡
84 printf("%c",ch);
85 fflush(stdout); //再次打印到屏幕
86 sleep(1);
87 semaphore_v(); //释放信号量
88 }
89 if(pid>0){
90 wait(NULL); //回收子进程
91 del_semvalue(); //删除信号量
92 }
93 printf("\nprocess %d finished.\n",getpid());
94 return 0;
95}
案例7:创建两个进程,使用共享内存机制实现这两个进程间的通信。 shm_w.c
1#include <stdio.h>
2#include <sys/ipc.h>
3#include <sys/shm.h>
4#include <sys/types.h>
5#include <unistd.h>
6#include <string.h>
7#define SEGSIZE 4096 //定义共享内存容量
8typedef struct{ //读写数据结构体
9 char name[8];
10 int age;
11} Stu;
12int main()
13{
14 int shm_id, i;
15 key_t key;
16 char name[8];
17 Stu *smap;
18 key = ftok("/", 0); //获取关键字
19 if (key == -1)
20 {
21 perror("ftok error");
22 return -1;
23 }
24 printf("key=%d\n", key);
25 //创建共享内存
26 shm_id = shmget(key, SEGSIZE, IPC_CREAT | IPC_EXCL | 0664);
27 if (shm_id == -1)
28 {
29 perror("create shared memory error\n");
30 return -1;
31 }
32 printf("shm_id=%d\n", shm_id);
33 smap = (Stu*)shmat(shm_id, NULL, 0); //将进程与共享内存绑定
34 memset(name, 0x00, sizeof(name));
35 strcpy(name, "Jhon");
36 name[4] = '0';
37 for (i = 0; i < 3; i++) //写数据
38 {
39 name[4] += 1;
40 strncpy((smap + i)->name, name, 5);
41 (smap + i)->age = 20 + i;
42 }
1 if (shmdt(smap) == -1) //解除绑定
2 {
3 perror("detach error");
4 return -1;
5 }
43 return 0;
44}
shm_r.c
6#include <stdio.h>
7#include <string.h>
8#include <sys/ipc.h>
9#include <sys/shm.h>
10#include <sys/types.h>
11#include <unistd.h>
12typedef struct{
13 char name[8];
14 int age;
15} Stu;
16int main()
17{
18 int shm_id, i;
19 key_t key;
20 Stu *smap;
21 struct shmid_ds buf;
22 key = ftok("/", 0); //获取关键字
23 if (key == -1)
24 {
25 perror("ftok error");
26 return -1;
27 }
28 printf("key=%d\n", key);
29 shm_id = shmget(key, 0, 0); //创建共享内存
30 if (shm_id == -1)
31 {
32 perror("shmget error");
33 return -1;
34 }
35 printf("shm_id=%d\n", shm_id);
36 smap = (Stu*)shmat(shm_id, NULL, 0); //将进程与共享内存绑定
37 for (i = 0; i < 3; i++) //读数据
38 {
39 printf("name:%s\n", (*(smap + i)).name);
40 printf("age :%d\n", (*(smap + i)).age);
41 }
42 if (shmdt(smap) == -1) //解除绑定
43 {
44 perror("detach error");
45 return -1;
46 }
47 shmctl(shm_id, IPC_RMID, &buf); //删除共享内存
48 return 0;
49}