进程间通信
一、进程间通信介绍
1.1 进程间通信目的


1.2 进程间通信发展

1.3 进程间通信分类

二、管道

三、匿名管道




3.1 示例代码
代码如下(示例):
例⼦:从键盘读取数据,写⼊管道,读取管道,写到屏幕
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main( void )
{
int fds[2];
char buf[100];
int len;
if ( pipe(fds) == -1 )
perror("make pipe"),exit(1);
// read from stdin
while ( fgets(buf, 100, stdin) ) {
len = strlen(buf);
// write into pipe
if ( write(fds[1], buf, len) != len ) {
perror("write to pipe");
break;
}
memset(buf, 0x00, sizeof(buf));
// read from pipe
if ( (len=read(fds[0], buf, 100)) == -1 ) {
perror("read from pipe");
break;
}
// write to stdout
if ( write(1, buf, len) != len ) {
perror("write to stdout");
break;
}
}
}
3.2 用fork来共享管道原理

3.3 站在文件描述符角度-深度理解管道

3.4 站在内核角度-管道本质

所以看待管道,就如同看待文件一样!
管道的使用和文件一致
3.5 管道样例
3.5.1 测试管道读写
代码如下(示例):
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
int main(int argc, char *argv[])
{
int pipefd[2];
if (pipe(pipefd) == -1)
ERR_EXIT("pipe error");
pid_t pid;
pid = fork();
if (pid == -1)
ERR_EXIT("fork error");
if (pid == 0) {
close(pipefd[0]);
write(pipefd[1], "hello", 5);
close(pipefd[1]);
exit(EXIT_SUCCESS);
}
close(pipefd[1]);
char buf[10] = {0};
read(pipefd[0], buf, 10);
printf("buf=%s\n", buf);
return 0;
}
3.5.2 创建进程池处理任务
代码如下(示例):
// channel.cpp
#ifndef __CHANNEL_HPP__
#define __CHANNEL_HPP__
#include <iostream>
#include <string>
#include <unistd.h>
// 先描述
class Channel
{
public:
Channel(int wfd, pid_t who) : _wfd(wfd), _who(who)
{
// Channel-3-1234
_name = "Channel-" + std::to_string(wfd) + "-" + std::to_string(who);
}
std::string Name()
{
return _name;
}
void Send(int cmd)
{
::write(_wfd, &cmd, sizeof(cmd));
}
void Close()
{
::close(_wfd);
}
pid_t Id()
{
return _who;
}
int wFd()
{
return _wfd;
}
~Channel()
{
}
private:
int _wfd;
std::string _name;
pid_t _who;
};
#endif
// processpool.hpp
#ifndef __PROCESS_POOL_HPP__
#define __PROCESS_POOL_HPP__
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <functional>
#include "Task.hpp"
#include "Channel.hpp"
// typedef std::function<void()> work_t;
using work_t = std::function<void()>;
enum
{
OK = 0,
UsageError,
PipeError,
ForkError
};
class ProcessPool
{
public:
ProcessPool(int n, work_t w)
: processnum(n), work(w)
{
}
// channels : 输出型参数
// work_t work: 回调
int InitProcessPool()
{
// 2. 创建指定个数个进程
for (int i = 0; i < processnum; i++)
{
// 1. 先有管道
int pipefd[2] = {0};
int n = pipe(pipefd);
if (n < 0)
return PipeError;
// 2. 创建进程
pid_t id = fork();
if (id < 0)
return ForkError;
// 3. 建⽴通信信道
if (id == 0)
{
// 关闭历史wfd
std::cout << getpid() << ", child close history fd: ";
for(auto &c : channels)
{
std::cout << c.wFd() << " ";
c.Close();
}
std::cout << " over" << std::endl;
::close(pipefd[1]); // read
// child
std::cout << "debug: " << pipefd[0] << std::endl;
dup2(pipefd[0], 0);
work();
::exit(0);
}
// ⽗进程执⾏
::close(pipefd[0]); // write
channels.emplace_back(pipefd[1], id);
// Channel ch(pipefd[1], id);
// channels.push_back(ch);
}
return OK;
}
void DispatchTask()
{
int who = 0;
// 2. 派发任务
int num = 20;
while (num--)
{
// a. 选择⼀个任务, 整数
int task = tm.SelectTask();
// b. 选择⼀个⼦进程channel
Channel &curr = channels[who++];
who %= channels.size();
std::cout << "######################" << std::endl;
std::cout << "send " << task << " to " << curr.Name() << ", 任务还
剩: " << num << std::endl;
std::cout << "######################" << std::endl;
// c. 派发任务
curr.Send(task);
sleep(1);
}
}
void CleanProcessPool()
{
// version 3
for (auto &c : channels)
{
c.Close();
pid_t rid = ::waitpid(c.Id(), nullptr, 0);
if (rid > 0)
{
3.6 管道读写规则

3.7 管道特点


四、命名管道


4.1 创建一个命名管道

4.2 匿名管道与命名管道的区别

4.3 命名管道的打开规则

五、system V共享内存
共享内存区是最快的IPC形式。⼀旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,
换句话说是进程不再通过执⾏进⼊内核的系统调⽤来传递彼此的数据



5.1 共享内存示意图

5.2 共享内存数据结构

5.3 共享内存函数






六、system V消息队列
ipc看到同一份资源,维护成为一个队列


七、system V信号量
7.1 并发编程



7.2 信号量






2009

被折叠的 条评论
为什么被折叠?



