当前位置: 首页 > news >正文

黄金网站app免费视频大全徐州手机网站建设公司

黄金网站app免费视频大全,徐州手机网站建设公司,网站怎么做搜狗排名,网站建设编辑叫什么岗位系列文章目录 文章目录 系列文章目录前言进程间通信介绍进程间通信目的进程间通信发展进程间通信分类进程通信的原理 管道什么是管道pipe管道通信特点简单设计 命名管道什么是命名管道mkfifostrcmp/strncasecmpunlinkgetch简单设计 共享内存什么是共享内存shmget/ftokipcsshmct…系列文章目录 文章目录 系列文章目录前言进程间通信介绍进程间通信目的进程间通信发展进程间通信分类进程通信的原理 管道什么是管道pipe管道通信特点简单设计 命名管道什么是命名管道mkfifostrcmp/strncasecmpunlinkgetch简单设计 共享内存什么是共享内存shmget/ftokipcsshmctlshmat/shmdt共享内存的特点 消息队列msgget/msgctlmsgsnd/msgrcv 信号量互斥等四个概念什么是信号量semget/semctlsemop 理解IPC总结 前言 进程通信是数据传输的重要方式。 进程间通信介绍 进程间通信目的 数据传输一个进程需要将它的数据发送给另一个进程 资源共享多个进程之间共享同样的资源。 通知事件一个进程需要向另一个或一组进程发送消息通知它它们发生了某种事件如进程终止时要通知父进程。 进程控制有些进程希望完全控制另一个进程的执行如Debug进程此时控制进程希望能够拦截另一个进程的所有陷入和异常并能够及时知道它的状态改变。 进程间通信发展 管道 System V进程间通信 POSIX进程间通信 进程间通信分类 管道 匿名管道pipe 命名管道 System V IPC System V 消息队列 System V 共享内存 System V 信号量 POSIX IPC 消息队列 共享内存 信号量 互斥量 条件变量 读写锁 进程通信的原理 让两个不同的进程进行通信前提条件是让两个进程看到同一份”资源“不违背进程的独立性并且由OS提供直接或间接提供。 任何进程通信手段 先让不同的进程看到同一份资源。通信方式 让一方写入一方读取完成通信过程。 管道 什么是管道 管道是Unix中最古老的进程间通信的形式。 我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”管道也是文件 。 who | wc -l // | 管道符创建子进程的时候只会浅拷贝进程相关的数据结构对象不会赋值父进程打开的文件对象 管道是一个OS提供的内存匿名文件以读写的方式打开。 fork之后需要确定数据的流向关闭不必要的fd。 因为只支持单向通信所以称之为管道。 pipe man pipe#include unistd.hint pipe(int pipefd[2]);On success, zero is returned. On error, -1 is returned, and errno is set appropriately.管道通信特点 单向通信半双工。 管道本质是文件因为fd的生命周期随进程的即管道的生命周期是随进程的。 管道通信通常用来进行具有”血缘“关系的进程进行通信常用于父子进程通信——pipe打开管道并不清楚管道的名字——匿名管道。 管道通信中写入的次数和读取的次数并不是严格匹配的读写没有强相关—— 面向字节流 管道具有一定的协同能力让reader和writer能够按照一定的步骤进行通信 —— 自带同步与互斥机制 如果read读取完毕了所有的管道数据如果对方不发就只能等待。 如果write端将管道写满了就不能写了管道容量有限。 关闭了写端读取完管道数据再读取read就会返回0表明读到了文件结尾。 如果写端一直再写读端关闭OS会通过信号的方式杀死一直在写入的进程。 当要一次写入的数据量不大于PIPE_BUF时linux将保证写入的原子性当要一次写入的数据量大于PIPE_BUF时linux将不再保证写入的原子性。 简单设计 父进程可以通过向子进程写入特定的消息唤醒子进程甚至让子进程定向的执行某种任务。 父进程要管理自己创建的管道和进程。 #include iostream #include string #include vector #include cassert #include unistd.h #include sys/wait.h #include sys/types.h #include Task.hpp using namespace std;const int gnum 3; Task t;class EndPoint { private:static int number; public:pid_t _child_id;int _write_fd;std::string processname; public:EndPoint(int id, int fd) : _child_id(id), _write_fd(fd){//process-0[pid:fd]char namebuffer[64];snprintf(namebuffer, sizeof(namebuffer), process-%d[%d:%d], number, _child_id, _write_fd);processname namebuffer;}std::string name() const{return processname;}~EndPoint(){} };int EndPoint::number 0;// 子进程要执行的方法 void WaitCommand() {while (true){int command 0;int n read(0, command, sizeof(int));if (n sizeof(int)){t.Execute(command);}else if (n 0){std::cout 父进程让我退出我就退出了: getpid() std::endl; break;}else{break;}} }void createProcesses(vectorEndPoint *end_points) {vectorint fds;for (int i 0; i gnum; i){// 1.1 创建管道int pipefd[2] {0};int n pipe(pipefd);assert(n 0);(void)n;// 1.2 创建进程pid_t id fork();assert(id ! -1);// 一定是子进程if (id 0){for(auto fd : fds) close(fd);//关闭其他进程的管道写端// std::cout getpid() 子进程关闭父进程对应的写端;// for(auto fd : fds)// {// std::cout fd ;// close(fd);// }// std::cout std::endl;// 1.3 关闭不要的fdclose(pipefd[1]);// 我们期望所有的子进程读取指令的时候都从标准输入读取// 1.3.1 输入重定向可以不做dup2(pipefd[0], 0);// 1.3.2 子进程开始等待获取命令WaitCommand();close(pipefd[0]);exit(0);}// 一定是父进程// 1.3 关闭不要的fdclose(pipefd[0]);// 1.4 将新的子进程和他的管道写端构建对象end_points-push_back(EndPoint(id, pipefd[1]));fds.push_back(pipefd[1]);} }int ShowBoard() {std::cout ########################################## std::endl;std::cout | 0. 执行日志任务 1. 执行数据库任务 | std::endl;std::cout | 2. 执行请求任务 3. 退出 | std::endl;std::cout ########################################## std::endl;std::cout 请选择# ;int command 0;std::cin command;return command; }void ctrlProcess(const vectorEndPoint end_points) {// 2.1 我们可以写成自动化的也可以搞成交互式的int num 0;int cnt 0;while(true){//1. 选择任务int command ShowBoard();if(command 3) break;if(command 0 || command 2) continue;//2. 选择进程int index cnt;cnt % end_points.size();std::string name end_points[index].name();std::cout 选择了进程: name | 处理任务: command std::endl;//3. 下发任务write(end_points[index]._write_fd, command, sizeof(command));sleep(1);} }void waitProcess(const vectorEndPoint end_points) {// 1. 我们需要让子进程全部退出 --- 只需要让父进程关闭所有的write fd就可以了// for(const auto ep : end_points) // for(int end end_points.size() - 1; end 0; end--)for(int end 0; end end_points.size(); end){std::cout 父进程让子进程退出: end_points[end]._child_id std::endl;close(end_points[end]._write_fd);waitpid(end_points[end]._child_id, nullptr, 0);std::cout 父进程回收了子进程: end_points[end]._child_id std::endl;} sleep(10);// 2. 父进程要回收子进程的僵尸状态// for(const auto ep : end_points) waitpid(ep._child_id, nullptr, 0);// std::cout 父进程回收了所有的子进程 std::endl;// sleep(10); }// #define COMMAND_LOG 0 // #define COMMAND_MYSQL 1 // #define COMMAND_REQEUST 2 int main() {vectorEndPoint end_points;// 1. 先进行构建控制结构, 父进程写入子进程读取 bug?createProcesses(end_points);// 2. 我们的得到了什么end_pointsctrlProcess(end_points);// 3. 处理所有的退出问题waitProcess(end_points);return 0; }#pragma once#include iostream #include vector #include unistd.h #include unordered_map// typedef std::functionvoid () func_t;typedef void (*fun_t)(); //函数指针void PrintLog() {std::cout pid: getpid() , 打印日志任务正在被执行... std::endl; }void InsertMySQL() {std::cout 执行数据库任务正在被执行... std::endl; }void NetRequest() {std::cout 执行网络请求任务正在被执行... std::endl; }// void ExitProcess() // { // exit(0); // }//约定每一个command都必须是4字节 #define COMMAND_LOG 0 #define COMMAND_MYSQL 1 #define COMMAND_REQEUST 2class Task { public:Task(){funcs.push_back(PrintLog);funcs.push_back(InsertMySQL);funcs.push_back(NetRequest);}void Execute(int command){if(command 0 command funcs.size()) funcs[command]();}~Task(){} public:std::vectorfun_t funcs;// std::unordered_mapstd::string, fun_t funcs; };命名管道 管道应用的一个限制就是只能在具有共同祖先具有亲缘关系的进程间通信。 如果我们想在不相关的进程之间交换数据可以使用FIFO文件来做这项工作它经常被称为命名管道。 命名管道是一种特殊类型的文件 什么是命名管道 mkfifo fifo//创建一个文件名为filo的命名管道有文件属性的内存级文件。 不同的进程打开同一个文件不会打开新的文件属性结构体对象。 两个进程打开同一个磁盘文件也可以构成磁盘通信信道。 为了不使用磁盘文件避免需要缓冲区刷新直接用内存级文件——命名管道文件来做”资源“。 命名管道与管道的原理一样。 命名管道必须要有文件名所以称为命名管道。 【总结】让不同的进程通过文件路径文件名看到同一个文件并打开就是看到了同一个”资源“。 mkfifo man 3 mkfifo#include sys/types.h #include sys/stat.hint mkfifo(const char *pathname, mode_t mode);On success mkfifo() returns 0. In the case of an error, -1 is returned (in which case, errno is set appropriately).strcmp/strncasecmp man strncasecmp#include strings.hint strcasecmp(const char *s1, const char *s2);int strncasecmp(const char *s1, const char *s2, size_t n);man strcmp#include string.hint strcmp(const char *s1, const char *s2);int strncmp(const char *s1, const char *s2, size_t n); unlink man 2 unlink#include unistd.hint unlink(const char *pathname);getch man getch#include curses.hint getch(void);简单设计 #pragma once#include iostream #include string#define NUM 1024const std::string fifoname ./fifo; uint32_t mode 0666; #include iostream #include cerrno #include cstring #include sys/types.h #include sys/stat.h #include fcntl.h #include unistd.h #include comm.hpp//少年们 我刚刚写了一个基于匿名管道的进程池 // 可不可以把它改成使用命名管道呢 int main() {// 1. 创建管道文件我们今天只需要一次创建umask(0); //这个设置并不影响系统的默认配置只会影响当前进程int n mkfifo(fifoname.c_str(), mode);if(n ! 0){std::cout errno : strerror(errno) std::endl;return 1;}std::cout create fifo file success std::endl;// 2. 让服务端直接开启管道文件int rfd open(fifoname.c_str(), O_RDONLY);if(rfd 0 ){std::cout errno : strerror(errno) std::endl;return 2;}std::cout open fifo success, begin ipc std::endl;// 3. 正常通信char buffer[NUM];while(true){buffer[0] 0;ssize_t n read(rfd, buffer, sizeof(buffer) - 1);if(n 0){buffer[n] 0;//std::cout client# buffer std::endl;printf(%c, buffer[0]);fflush(stdout);}else if(n 0){std::cout client quit, me too std::endl;break;}else {std::cout errno : strerror(errno) std::endl;break;}}// 关闭不要的fdclose(rfd);unlink(fifoname.c_str());return 0; }#include iostream #include cstdio #include cerrno #include cstring #include cassert #include sys/types.h #include sys/stat.h #include fcntl.h #include unistd.h // #include ncurses.h #include comm.hppint main() {//1. 不需创建管道文件我只需要打开对应的文件即可int wfd open(fifoname.c_str(), O_WRONLY);if(wfd 0){std::cerr errno : strerror(errno) std::endl;return 1;}// 可以进行常规通信了char buffer[NUM];while(true){// std::cout 请输入你的消息# ;// char *msg fgets(buffer, sizeof(buffer), stdin);//C库函数读取的是字符串会处理\0,系统调用处理字节流不会处理\0.// assert(msg);// (void)msg;// int c getch();// std::cout c std::endl;// if(c -1) continue;system(stty raw);int c getchar();system(stty -raw);//std::cout c std::endl;//sleep(1);//buffer[strlen(buffer) - 1] 0;// abcde\n\0// 012345//if(strcasecmp(buffer, quit) 0) break;ssize_t n write(wfd, (char*)c, sizeof(char));assert(n 0);(void)n;}close(wfd);return 0; }共享内存 【system V共享内存】 共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间这些进程间数据传递不再涉及到\内核换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。 什么是共享内存 让不同的进程先看到同一份资源——内存块–共享内存。 虚拟进程空间的共享区映射同一块物理内存。 在任意一个时刻可能有多个共享内存在被用来进行通信所以系统中一定存在很多shm同时存在OS要管理所有的共享内存。所以共享内存不仅仅会在内存中开辟空间OS也会构建对应的描述共享内存的结构体对象 共享内存 共享内存的内核数据结构伪代码struct shm) 真正开辟的内存空间 shmget/ftok man shmget#include sys/ipc.h #include sys/shm.hint shmget(key_t key, size_t size, int shmflg);On success, a valid shared memory identifier is returned. On errir, -1 is returned, and errno is set to indicate the error.man ftok #include sys/types.h #include sys/ipc.hkey_t ftok(const char *pathname, int proj_id); // pathname:路径字符串 proj_id:项目ID让两个进程映射同一个内存块。 传入同样的参数形成一样key_t一个进程用key_t创建一个内存块并映射另一个进程用key_t映射该内存块使两个进程地址空间映射同一个内存块。 key_t是在内核中使用的用数字来标识唯一的内存块。 key vs shmidkey类比文件inode编号shmid类比文件的fd。所以在用户层的操作都是用shmid。 ipcs [admin1VM-4-17-centos linux_code]$ ipcs------ Message Queues -------- key msqid owner perms used-bytes messages //消息队列 ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status //共享内存 ------ Semaphore Arrays -------- key semid owner perms nsems //信号量//显示ipc通信系统所支持的三种ipc通信策略 //1.key:表示共享内存的key //2.shmid:表示共享内存的编号 //3.owner表示创建共享内存的用户 //4.perms:表示共享内存的使用权限 //5.bytes:表示共享内存的大小 //6.nattch表示连接到共享内存的进程数 //7.status表示共享的状态不显示则为正常使用显示dest表示共享内存已被删除但任有用户使用[admin1VM-4-17-centos linux_code]$ ipcs -m //查看共享内存 ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status //-m 针对共享内存的操作 //-q 针对消息队列的操作 //-s 针对消息队列的操作 //-a 针对所有资源的操作[admin1VM-4-17-centos linux_code]$ ipcrm -m 196611 //删除shmid为196611的共享内存 shmctl man shmctl#include sys/ipc.h #include sys/shm.hint shmctl(int shmid, int cmd, struct shmid_ds *buf);//删除共享内存shmat/shmdt man shmat/shmdt#include sys/types.h #include sys/shm.hvoid *shmat(int shmid, const void *shmaddr, int shmflg); //关联共享内存int shmdt(const void *shmaddr); //去关联共享内存共享内存的特点 创建共享内存的进程已经退出了但我们发现共享内存一定还存在共享内存的生命周期不随进程随OS。 一旦共享内存映射到进程的地址空间该共享内存就直接被所有的进程看到了。可以让进程通信的时候减少拷贝次数所以共享进程是所有进程通信方式中速度最快的。 共享内存没有任何的保护机制同步互斥。因为管道通过系统接口通信共享内存直接通信。 消息队列 msgget/msgctl man msgget#include sys/types.h #include sys/ipc.h #include sys/msg.hint msgget(key_t key, int msgflg);#include sys/types.h #include sys/ipc.h #include sys/msg.hint msgctl(int msqid, int cmd, struct msqid_ds *buf);msgsnd/msgrcv #include sys/types.h#include sys/ipc.h#include sys/msg.hint msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);信号量 互斥等四个概念 我们把大家都能看到的资源称为”公共资源“。 互斥任何一个时刻都只允许一个执行流在进行共享资源的访问——加锁。 我们把任何一个时刻都只允许一个执行流在进行访问的共享资源称为”临界资源“。 临界资源是要通过代码访问的凡是访问临界资源的代码叫做”临界区“。 原子性要么不做要么做完只有两种确定状态的属性。 什么是信号量 任何计技术都有自己的应用场景。 看电影之前先要买票。 买票的本质功能1. 对坐位资源的预定机制 2. 确保不会因为多放出去特定的座位资源而导致冲突。 假设一个放映厅只有一个座位→互斥 信号量/信号灯本质就是一个计数器描述资源数量的计数器。 任何一个执行流想访问临界资源的一个子资源的时候不能直接访问。先申请信号量资源–count只要我申请信号量成功我就一定未来能够拿到一个子资源。如果信号量用完了即没有成功申请就会挂起阻塞进程。—— P操作。 成功申请后进入自己的临界区访问对应的临界资源。 释放信号量资源count只要将计数器增加就表示将我们对应的资源进行了归还。阻塞的进程就可以继续申请并执行了。—— V操作。 进程通过执行代码来申请每个进程都要遵守这个规则。 所有的进程都得先看到信号量——共享资源——必须保证自己的操作/–是原子的 两个进程可以看到同一个count即让不同的进程看到同一个”计数器“资源。所以信号量被归类到了进程间通信 如果这个计数器是1呢这就是二元信号量完成了互斥功能互斥的本质就是将临界资源独立使用 semget/semctl man semget#include sys/types.h #include sys/ipc.h #include sys/sem.hint semget(key_t key, int nsems, int semflg);#include sys/types.h #include sys/ipc.h #include sys/sem.hint semctl(int semid, int semnum, int cmd, ...);semop man semop#include sys/types.h #include sys/ipc.h #include sys/sem.hint semop(int semid, struct sembuf *sops, unsigned nsops);理解IPC “多态” 总结 进程通信的本质是让不同进程看到同一份”资源“。 如果你真的愿意为自己的梦想去努力最差的结果不过是大器晚成。
http://www.w-s-a.com/news/367164/

相关文章:

  • 电子商务网站建设与管理试卷6江门网站建设联系电话
  • 公司的网站建设做什么费用四川圣泽建设集团有限公司网站
  • 为什么网站很少做全屏福利WordPress网站自动采集源码
  • 网站备案法律diy
  • 淘宝客如何新建网站物业管理系统app
  • 品牌网站建设策重大军事新闻视频
  • 廊坊建设网站的公司wordpress清理无用缩略图
  • 桓台网站建设公司首钢建设二建设公司网站
  • 网站建设添加背景命令前端如何优化网站性能
  • 设置网站域名中山画册设计公司
  • 三更app下载网站东莞网站制作公
  • 做图书馆网站模板网站建设文化策划方案
  • 惠州城乡住房建设厅网站服装设计自学零基础
  • 网站建设常态化工作机制广州骏域网络
  • h5婚纱摄影网站模板wordpress 显示下列项目
  • 广告网站推广销售北京最新消息发布
  • 完整网站源码asp拨打12355可以找团员密码吗
  • 北京有多少家网站怎么自己在百度上做网站
  • 怎样围绕网站专题发展来做ppt网站建设回龙观
  • 网站配置服务Wordpress红色网站源码
  • 外贸网站建设内容包括软件开发公司流程
  • 做中医药网站有前景吗企业网站优化公司
  • 四川建设设计公司网站海南澄迈县
  • 邳州做网站梵克雅宝项链官网价格图片
  • dede网站收录滦平县建设局网站
  • 上海网站建设开发公注册公司要求什么条件
  • 安徽汽车网网站建设wordpress 知乎
  • 网站建设的功能都需要有哪些在线平台
  • 湖南岳阳网站开发网络公司石家庄做网站的公司哪个好
  • 西安市做网站的公司门户网站对应序号是什么