进程间通信
常用的进程间通信方式包括:管道、 消息队列、共享
内存、信号量、套接字等 。其中,前面 4种主要用于同1 台机器上的进程间通信,而套接字
则主要用于不同机器之间的网络通信 。
管道
管道是 Linux 支持的最初
UNIX IPC 形式之一,具有以下特点:
- 数据只能由一个进程流向另一个进程(其中一个读管道, 个写管道);如果要进行
双工通信,则需要建立两个管道 - 管道只能用于父子进程或者兄弟进程间通信,也就是说管道只能用于具有亲缘关系的进程间通信
利用管道进行通信:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
int main()
{
int fd[2];
pid_t pid;
char buf[256];
int returned_count;
pipe(fd);//创建无名管道
pid = fork();//创建子进程
if(pid < 0)
{
printf("error in fork\n");
exit(1);
}
else if(pid == 0)
{
//child process
printf("in child process...\n");
close(fd[0]);//child process write to parent process,close read pipe
write(fd[1],"hello world",strlen("hello world"));
exit(0);
}else{
//parent process
close(fd[1]);
returned_count = read(fd[0],buf,sizeof(buf));
printf("%d bytes of data received from child process:%s\n",returned_count,buf);
}
return 0;
}
消息队列
消息队列用于运行于同一台机器上的进程间通信,它和管道很相似,是一个在系统内核
中用来保存消息的队列,它在系统内核中是以消息链表的形式出现 消息链表中节点的结构
msg 声明
共享内存
共享内存就是允许两个不相关的进程访问同 1个逻辑内存。 共享 内存是在两
个正在运行的进程之间共享和传递数据的非常有效的方式。 不同进程之间共享的内存通
常安排在同1 段物理内存中。 进程可以将同一段共享内存连接到它们 自己 的地址空间中,所
有进程都可以访问共享内存中的地址。
而如果某个进程向共享内存写入数据,所做的改动将影响共享
内存的任何其他进程。
不过,共享内存并未提供同步机制,所以通常需要其他的机制来同步对共享内存的访问。
利用共享内存进行通信:
producer.cpp1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
int main()
{
int shmid;
shmid = shmget((key_t)1234,sizeof(struct shared_use_st),0666|IPC_CREAT);
if(shmid == -1)
{
fprintf(stderr,"shmget failed\n");
exit(EXIT_FAILURE);
}
void *shared_memory = NULL;
shared_memory = shmat(shmid,NULL,0);
if(shared_memory == (void *)-1)
{
fprintf(stderr,"shmat failed\n");
exit(EXIT_FAILURE);
}
printf("memory attached at %X\n",(long)shared_memory);
struct shared_use_st *shared_stuff;
shared_stuff = (struct shared_use_st*)shared_memory;
int running = 1;
char buffer[TEXT_SZ];
while(running)
{
while(shared_stuff->written == 1)
{
sleep(1);
printf("waiting for client...\n");
}
printf("enter some text: ");
fgets(buffer,TEXT_SZ,stdin);
strncpy(shared_stuff->text,buffer,TEXT_SZ);
shared_stuff->written = 1;
if(strncmp(shared_stuff->text,"end",3) == 0)
{
running = 0;
}
}
if(shmdt(shared_memory) == -1)
{
fprintf(stderr,"shmdt failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
consumer.cpp1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
int main()
{
int shmid;
srand((unsigned int)getpid());
shmid = shmget((key_t)1234,sizeof(struct shared_use_st),0666|IPC_CREAT);
if(shmid == -1)
{
fprintf(stderr,"shmget failed\n");
exit(EXIT_FAILURE);
}
void *shared_memory = NULL;
shared_memory = shmat(shmid,NULL,0);
if(shared_memory == (void *)-1)
{
fprintf(stderr,"shmat failed\n");
exit(EXIT_FAILURE);
}
printf("memory attached at %X\n",(long)shared_memory);
struct shared_use_st *shared_stuff;
shared_stuff = (struct shared_use_st*)shared_memory;
shared_stuff->written = 0;
int running = 1;
while(running)
{
if(shared_stuff->written)
{
printf("you wrote:%s",shared_stuff->text);
sleep(rand()%4);
shared_stuff->written = 0;
if(strncmp(shared_stuff->text,"end",3) == 0)
{
running = 0;
}
}
}
if(shmdt(shared_memory) == -1)
{
fprintf(stderr,"shmdt failed\n");
exit(EXIT_FAILURE);
}
if(shmctl(shmid,IPC_RMID,0) == -1)
{
fprintf(stderr,"shmctl failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
头文件shm_com.h1
2
3
4
5
6
struct shared_use_st{
int written;
char text[TEXT_SZ];
};
信号量
多线程同步中提及了信号 ,但用于多线程同步的信号量是
POSIX 信号 ,而此信号量是 SYSTEM 信号 ,本质上说这两种都是用户态进
程可以使用的信号量 。
共享内存是进程间通信的最快的方式,但是共享内存的同步问题自身无法解决(即进程该何时去共享内存取得数据,而何时不能取),但用信号量即可轻易解决这个问题。