很久以前学的进程通信,今天根据自己的理解将其分享出来。
1.管道:
是一种最简单的IPC机制,由
#include<unsitd.h>
pipe(int filedes[2]); 函数创建:
调用pipe函数在内核中申请开辟一块缓冲区(管道),用于通信,有一个写端和一个读端
简单的程序:
//打开管道,写入
#include<stdio.h>
#include<fcntl.h>
#include<stdlib.h>
int main()
{
int fd;
int count = 5;
int len;
pid_t pid = 0;
char *path = "/home/gq/myfifo";
fd = open(path,O_WRONLY);
if(fd == -1)
{
perror("open myfifo");
return 1;
}
while(count--){
len = write(fd,"hello",6);
printf("write return len %d\n",len);
sleep(1);
}
close(fd);
return 0;
}
//从管道中读东西,只有当管道的读端和写端都打开的时候,管道才是通的,才能执行
int main()
{
int fd;
char buff[BUFSIZ];
int len;
pid_t pid = 0;
char *path = "/home/gq/myfifo";
fd = open(path,O_RDONLY);
if(fd == -1)
{
perror("open myfifo");
return 1;
}
//while(1);
while(1)
{
len = read(fd,buff,BUFSIZ);
if(len>0)
printf("%s\n",buff);
}
close(fd);
return 0;
}
//如果是一个写,多个读,则多个的进程是随机的。
2.共享内存:
#include<sys/shm.h>
1>.为了在不同的进程中访问到相同的内存空间,首先获得唯一的key值。
#define PRJ_SHM_ID 'a'
#define PRJ_SEM_ID 'b'
key_t shmkey = ftok("/home", PRJ_SHM_ID);
key_t semkey = ftok("/home", PRJ_SEM_ID);
2>.向内存申请共享内存:
int shmid = shmget(shmkey,10,SHM_W|SHM_R|IPC_CREAT);
if(shmid < 0) perrno("shmget"); return 1;
3>.获取指向共享内存的指针
char *shmptr;
shmptr = (char *)shmat(shmid,0,0);
if(shmptr == NULL)
{
perror("shmat");
return 1;
}
4>.可以直接使用指针对内存进行读写操作。
/*两种输入*/
int i;
while(1){
char *p = shmptr;
for(i=0;i<128;i++){
//*p++ = '0' + i%10;
*p++ = 'a' + i%26;
usleep(1000);
}
}
/* 上面一种可能会造成打印的乱码*/
strncpy(shmptr,"hello",6);
printf("%s\n",shmptr);
6>.删除所创建的共享内存
smctl(semid, IPC_RMID, NULL);
3.信号量signal:
#include<sys/sem.h>
1>.创建key值,可参考共享内存。
2>.在内核中创建信号量:
int semid = semget(key, 1, IPC_CREAT);
if(semid < 0) perrno("semget"); return 1;
3>.设置信号量值
semctl(semid,0,SETVAL,1);
4>.查看并修改信号量的值
struct sembuf sem1_wait = {0,-1,SEM_UNDO};
struct sembuf sem1_wakeup = {0,1,SEM_UNDO};
把信号量值由1变为0
semop(semid,sem1_lock,1);
如果发现信号量是1,则变为0,马上退出。如果发现信号量是0,则阻塞,直到有人把0变成1,才会获得。
把信号量值由0变到1
semop(semid, sem1_unlock, 1);
5>. 如果信号量不再使用了,可以删除
semctl(semid, IPC_RMID, NULL);
4.消息队列:
#include <sys/msg.h>
struct my_msg_st{
long int msg_type;
char some_text[BUFSIZ];
};
int msgid;
msgid = msgget(key_t key, int msgflg);
struct my_msg_st some_data;
while(1){
int msgrcv(int msgid, &some_data , BUFSIZ, 'a' ,0);
printf("%d,%s\n",some_data.msg_type, some_data.some_text);
}
while(1){
some_data.msg_type = 'a';
strcpy(some_data.some_text, "hello");
int msgsnd(msgid, &some_data, 6, 0);
}
int msgctl();
msgrcv, msgsnd的第五个参数依然是是控制函数行为的标志,取值可以是:
0,表示忽略;
IPC_NOWAIT,如果消息队列为空,则返回一个ENOMSG,并将控制权交回调用函数
的进程。如果不指定这个参数,那么进程将被阻塞直到函数可以从队列中得到符合条件的
消息为止。如果一个client 正在等待消息的时候队列被删除,EIDRM 就会被返回。如果进
程在阻塞等待过程中收到了系统的中断信号,EINTR 就会被返回。
MSG_NOERROR,如果函数取得的消息长度大于msgsz,将只返回msgsz 长度的信息,
剩下的部分被丢弃了。如果不指定这个参数,E2BIG 将被返回,而消息则留在队列中不被取出。
当消息从队列内取出后,相应的消息就从队列中删除了。