c++ 网络编程(三)TCP/IP LINUX/windows 进程间的通信原理与实现代码 基于多进程的服务端实现

 原文作者:aircraft

原文链接:upload/201809101710048824.jpg" alt="进程的5种状态" style="margin: 0px; padding: 0px; border: none; max-width: 800px; height: auto;" /> 
与上面的5种状态不同,在Linux中使用top命令查看进程也有5种状态,但它是以不同的角度来描述进程状态: 
R:运行状态,正在运行或在运行队列中等待 
S:可中断(自愿)的睡眠状态,在等待某事件发生才可唤醒。如网页服务器的httpd进程,在客户端(浏览器)发出请求之前,服务器无事可做,选择睡眠。是程序角度的睡眠,程序本身控制自己的运行状态 
D:不可中断(非自愿)的睡眠状态,有时两个进程试图同时访问同一系统资源,例如一个进程试图从磁盘数据块上读取信息,而另一个进程正在向该数据块写入信息。在这种情况下,内核迫使进程进入非自愿睡眠状态,该进程并没有自愿选择睡眠。当资源被释放时,内核会唤醒进程并将其设置为可运行状态。虽然进程断的进入和离开非自愿睡眠,但是它们通常不会在该状态停留太久。因此,除了在高负荷的系统上,用户通常看不到处于非自愿睡眠状态的进程。 
T:停止或跟踪状态,进程收到SIGSTOP, SIGSTP, SIGTIN, SIGTOU信号后停止运行 
Z:僵死状态,子进程先于父进程退出,同时父进程又没有调用wait()或waitpid(),则该子进程将成为僵尸进程。为了防止产生僵尸进程,在fork子进程之后我们都要在父进程wait它们

2 线程概念

早期的计算机系统只有进程,没有线程,后来发现进程切换的开销有点大,于是产生了线程(也称轻量级进程),线程切换比进程切换的开销要小很多。线程是程序执行中一个单一的顺序控制流,是程序执行流的最小单元,是处理器调度和分派的基本单位,是进程中代码的不同执行路线,一个进程可以有多个线程。 
现在的处理器一般是双核或四核的,每个处理核心对应一个内核线程,但是我们经常看到双核心四线程或四核心八线程的描述,这其实是采用了超线程技术将一个物理处理核心模拟成两个逻辑处理核心,对应两个内核线程,所以采用了超线程技术的CPU在操作系统中看到的CPU数量是实际物理CPU数量的两倍。这里讲到了内核线程,内核线程(Kernel Thread, KLT)就是直接由操作系统内核支持的线程,这种线程由内核来完成线程切换,内核通过操作调度器对线程进行调度,并负责将线程的任务映射到各个处理器上。而用户程序一般是创建用户线程,然后用户线程调用内核线程,在现在流行的操作系统中,用户线程和内核线程是多对多的映射调用关系。

3 进程、线程的区别与联系

一个程序至少产生一个进程,一个进程至少产生一个线程,线程再映射到内核线程,在处理器上完成计算任务。 
进程与线程的区别,关键就在于它们独立拥有的资源不同,因此就体现出了不同的特性,主要有以下几方面的不同: 
(1)资源 
进程作为除CPU以外系统资源的分配单位,每个进程都拥有独立的地址空间和资源,因此一个进程崩溃不会引起其他进程的运行,就好像是不同程序创建的不同进程互不影响一样; 
线程作为CPU的分配单位,是被系统独立调度和分派的基本单位,本身仅拥有CPU中的寄存器和线程函数调用需要的堆栈区这一点点资源,其他资源如代码、公有数据、文件描述符等都是与其他线程共享的进程资源,所以一个线程崩溃,整个进程都崩溃。 
(2)系统开销 
由于每个进程都拥有独立的地址空间和资源,因此进程的创建和撤销都需要资源的分配和回收,系统开销大; 
每个线程仅仅拥有一点必不可少的资源,所以创建和撤销都很快。 
(3)通信方式 
进程之间主要有6种通信方式:管道、信号、消息队列、共享内存、信号量、socket; 
线程之间主要有3种通信方式:锁机制(包括互斥锁、条件变量、读写锁)、信号量机制、信号机制。 
线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制。 
通信方式的内容写得不够详细,后续再补充,下面这些是暂时记录的内容:

信号量:一个初始值为N的信号量允许N个线程并发访问。线程访问资源时首先获取信号量锁,进行如下操作: 
1. 将信号量的值减1; 
2. 如果信号量的值小于0,则进入等待状态,否则继续执行; 
访问资源结束之后,线程释放信号量锁,进行如下操作: 
1. 将信号量的值加1; 
2. 如果信号量的值小于1(等于0),唤醒一个等待中的线程; 
同步:多个事件一起开始,一起结束(一刀切); 
异步:多个事件各走各的,完成了通知一下控制中心; 
阻塞:所申请资源被占用、启动IO传输未完成,必须等待资源或事件完成才可以进行下一步称为阻塞; 
挂起:挂起是主动的,一般需要用挂起函数进行操作,若没有resume的动作,则此任务一直不会ready,而阻塞是因为资源被其他任务抢占而处于休眠态。

 

 

一.进程间通信的基本概念

进程间通信意味着两个不同进程间可以交换数据,操作系统中应提供两个进程可以同时访问的内存空间。

 

通过管道实现进程间通信

基于管道(PIPE)的进程间通信结构模型:

                                                复制代码

#include<stdio.h> #include<unistd.h>#define BUF_SIZE 30 int main(int argc, char *argv[]) {     int fds[2];     char str[] = "Who are you?";     char buf[BUF_SIZE];     pid_t pid;       pipe(fds);                //创建管道,fds数组中保存用于I/O的文件描述符    pid = fork();            //子进程将同时拥有管道的I/O文件描述符。    if (pid == 0)     {         write(fds[1],str,sizeof(str));        //fds[1]为管道入口    }     else<
                    
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信