1. 操作系统

1.1.1. linux惊群效应

点击显示

是什么: 惊群效应也叫雷鸣群体效应,简言之,就是多进程(线程)在同时阻塞等待同一个事件的时候(休眠状态),如果等待的这个事件发生,那么他会唤醒等待的所有进程(线程), 但是最终只可能有一个进程(线程)获得这个时间的"控制权",对该事件进行处理,而其他进程(线程)获得"控制权"失败,只能重新进入休眠状态,这种现象和性能浪费叫做惊群

消耗:

  • 系统对用户进程/线程频繁地做无效的调度,上下文切换系统性能大打折扣
  • 为了确保只有一个线程得到资源,用户必须对资源进行加锁保护,进一步加大系统开销

linux惊群效应详解

1.1.2. 多线程的优缺点

点击显示

优点:

  • 能适当提高程序的执行效率
  • 能适当提高资源的利用率(CPU&内存)
  • 线程上的任务执行后自动销毁 缺点:
  • 开启线程需要占用一定的内存空间
  • 如果开启大量的线程,会占用大量的内存空间,降低程序的性能
  • 线程越多,cpu在调用线程上的开销就越大
  • 程序设计更加复杂,比如线程简的通信,多线程的数据共享

https://www.jianshu.com/p/1556a462be72

1.1.3. Linux I/O模型一共有哪些?

点击显示

O模型主要由阻塞式I/O模型,非阻塞式I/O模型,I/O复用模型,信息驱动式I/O模型,异步I/O模型。

  • 阻塞式I/O模型

    用户态进程调用recvfrom系统调用来接受数据,如果当前内核中数据没有准备好,那么会一直等待,不会进行其他操作,直到内核中的数据准备好,将数据拷贝到用户空间内存,然后recvfrom返回成功的信号,此时用户态进行才解除阻塞的状态,处理收到的数据。

  • 非阻塞时I/O模型

    在非阻塞式I/O模型中,当进程等待内核的数据,而当该数据未到达的时候,进程会不断询问内核,直到内核准备好数据。

    用户态进程调用recvfrom接收数据,当前并没有数据报文产生,此时recvfrom返回EWOULDBLOCK,用户态进程会一直调用recvfrom询问内核,待内核准备好数据的时候,之后用户态进程不再询问内核,待数据从内核复制到用户空间,recvfrom成功返回,用户态进程开始处理数据。

  • I/O多路复用模型

    I/O复用指的是多个I/O连接复用一个进程。

    最初级的I/O复用,就是一个进程对应多个连接,每次从头至尾进行遍历,判断是否有I/O事件需要处理,有的话就进行处理,缺点是效率比较低,如果一直没有事件进来,会导致CPU空转。

    • 升级版的I/O复用模型

      当没有I/O事件时,进程处于阻塞状态,当有I/O事件时,就会有一个代理去唤醒进程,去进行轮询,来处理I/O事件。(这里的代理也就是select和poll,select只能观察1024个连接,poll可以观察无限个连接)

      epoll是对select和poll的升级版,解决了很多问题,是线程安全的,而且可以通知进程是哪个Socket连接有I/O事件,提高了查找效率。

      • epoll和select/poll最大区别是

        • epoll内部使用了mmap共享了用户和内核的部分空间,避免了数据的来回拷贝
        • epoll基于事件驱动,epoll_wait只返回发生的事件避免了像select和poll对事件的整个轮寻操作。
  • 信息驱动式I/O模型

    是非阻塞的,当需要等待数据时,用户态进程会给内核发送一个信号,告知自己需要的数据,然后就去执行其他任务了,内核准备好数据后,会给用户态发送一个信号,用户态进程收到之后,会立马调用recvfrom,等待数据从从内核空间复制到用户空间,待完成之后recvfrom返回成功指示,用户态进程才处理数据。

  • 异步I/O模型

    与信息驱动式I/O模型区别在于,是在数据从内核态拷贝到用户空间之后,内核才通知用户态进程来处理数据。在复制数据到用户空间这个时间段内,用户态进程也是不阻塞的。

1.1.4. 同步与异步的区别是什么?

点击显示

同步与异步的区别在于调用结果的通知方式上。 同步执行一个方法后,需要等待结果返回,然后继续执行下去。 异步执行一个方法后,不会等待结果的返回,调用方定时主动去轮询调用结果或者被调用方在执行完成后通过回调来通知调用方。

1.1.5. 阻塞与非阻塞的区别是什么?

点击显示

阻塞与非阻塞的区别在于进程/线程在等待消息时,进程/线程是否是挂起状态。 阻塞调用在发出去后,消息返回之前,当前进程/线程会被挂起,直到有消息返回,当前进/线程才会被激活。 非阻塞调用在发出去后,不会阻塞当前进/线程,而会立即返回,可以去执行其他任务。

1.1.6. 进程和线程的区别?

点击显示
  • 简而言之,一个程序至少有一个进程,一个进程至少有一个线程
  • 线程的划分尺度小于进程,使得多线程程序的并发性高
  • 另外,进程在执行过程中拥有独立的内存单元,每个独立的线程有一个程序运行的入口,顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在程序中,由应用程序提供多个线程执行控制
  • 从逻辑角度看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行,但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配

  • 进程和线程的关系: 线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除,线程可与属于同一进程的其他 线程共享进程所拥有的全部资源,但是其本身基本上不拥有系统资源,只拥有一点在运行中必不可少的信息(如程序计数器,一组寄存器和栈)

1.1.7. 孤儿进程,僵尸进程,守护进程?

点击显示
  • 孤儿进程

    根据维基百科的解释,孤儿进程指的是在其父进程执行完成或被终止后仍继续运行的一类进程。

    孤儿进程与僵尸进程是完全不同。孤儿进程借用了现实中孤儿的概念,也就是父进程不在了,子进程还在运行,这时我们就把子进程的PPID设为1。操作系统会创建进程号为1的init进程,它没有父进程也不会退出,可以收养系统的孤儿进程。

    在现实中用户可能刻意使进程成为孤儿进程,这样就可以让它与父进程会话脱钩,成为后面会介绍的守护进程。

  • 僵尸进程

    当一个进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态

    一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵尸进程。

  • 守护进程

    • 守护(Daemon)进程

      我们可以认为守护进程就是后台服务进程,因为它会有一个很长的生命周期提供服务,关闭终端不会影响服务,也就是说可以忽略某些信号。

    • 实现守护进程 首先要保证进程在后台运行,可以在启动程序后面加&,当然更原始的方法是进程自己fork然后结束父进程。

            if (pid=fork()) {
              exit(0); // Parent process
            }
      

      然后是与终端、进程组、会话(Session)分离。每个进程创建时都绑定一个终端,而且属于一个进程组(进程组也有GID不过等同进程组长的PID),这些进程组在一个会话中,如果是子进程一般会从父进程继承这些信息,想要与环境分离可以使用以下的系统调用。

      setsid();

      同样地我们会从父进程继承文件掩码(mask),可以手动清理掩码。

      umask(0);

      如果需要我们可以改变当前工作目录,避免运行时必须使用当前所在的文件系统。

    • 使用Nohup nohup命令,是让程序以守护进程运行的方式之一,程序运行后忽略SIGHUP信号,也就说关闭终端不会影响进程的运行。

      类似的命令还有disown

1.1.8. 线程间的通信、同步方式与进程间通信方式?

点击显示

线程间的通信方式

  • 使用全局变量

    主要由于多个线程可能更改全局变量,因此全局变量最好声明为volatile

  • 使用消息实现通信

    在Windows程序设计中,每一个线程都可以拥有自己的消息队列(UI线程默认自带消息队列和消息循环,工作线程需要手动实现消息循环),因此可以采用消息进行线程间通信sendMessage,postMessage。

    1)定义消息#define WM_THREAD_SENDMSG=WM_USER+20;

    2)添加消息函数声明afx_msg int OnTSendmsg();

    3)添加消息映射ON_MESSAGE(WM_THREAD_SENDMSG,OnTSM)

    4)添加OnTSM()的实现函数;

    5)在线程函数中添加PostMessage消息Post函数

  • 使用事件CEvent类实现线程间通信

    Event对象有两种状态:有信号和无信号,线程可以监视处于有信号状态的事件,以便在适当的时候执行对事件的操作。

    1)创建一个CEvent类的对象:CEvent threadStart;它默认处在未通信状态;

    2)threadStart.SetEvent();使其处于通信状态;

    3)调用WaitForSingleObject()来监视CEvent对象

线程间的同步方式

各个线程可以访问进程中的公共变量,资源,所以使用多线程的过程中需要注意的问题是如何防止两个或两个以上的线程同时访问同一个数据,以免破坏数据的完整性。数据之间的相互制约包括

  1. 直接制约关系,即一个线程的处理结果,为另一个线程的输入,因此线程之间直接制约着,这种关系可以称之为同步关系

  2. 间接制约关系,即两个线程需要访问同一资源,该资源在同一时刻只能被一个线程访问,这种关系称之为线程间对资源的互斥访问,某种意义上说互斥是一种制约关系更小的同步

线程间的同步方式有四种

  • 临界区

    临界区对应着一个CcriticalSection对象,当线程需要访问保护数据时,调用EnterCriticalSection函数;当对保护数据的操作完成之后,调用LeaveCriticalSection函数释放对临界区对象的拥有权,以使另一个线程可以夺取临界区对象并访问受保护的数据。

    PS:关键段对象会记录拥有该对象的线程句柄即其具有“线程所有权”概念,即进入代码段的线程在leave之前,可以重复进入关键代码区域。所以关键段可以用于线程间的互斥,但不可以用于同步(同步需要在一个线程进入,在另一个线程leave)

  • 互斥量

    互斥与临界区很相似,但是使用时相对复杂一些(互斥量为内核对象),不仅可以在同一应用程序的线程间实现同步,还可以在不同的进程间实现同步,从而实现资源的安全共享。

    PS:1、互斥量由于也有线程所有权的概念,故也只能进行线程间的资源互斥访问,不能由于线程同步; 2、由于互斥量是内核对象,因此其可以进行进程间通信,同时还具有一个很好的特性,就是在进程间通信时完美的解决了"遗弃"问题

  • 信号量

    信号量的用法和互斥的用法很相似,不同的是它可以同一时刻允许多个线程访问同一个资源,PV操作

    PS:事件可以完美解决线程间的同步问题,同时信号量也属于内核对象,可用于进程间的通信

  • 事件 事件分为手动置位事件和自动置位事件。事件Event内部它包含一个使用计数(所有内核对象都有),一个布尔值表示是手动置位事件还是自动置位事件,另一个布尔值用来表示事件有无触发。由SetEvent()来触发,由ResetEvent()来设成未触发。

    PS:事件是内核对象,可以解决线程间同步问题,因此也能解决互斥问题

进程间通信方式

进程间通信又称IPC(Inter-Process Communication),指多个进程之间相互通信,交换信息的方法。根据进程通信时信息量大小的不同,可以将进程通信划分为两大类型:

  1. 低级通信,控制信息的通信(主要用于进程之间的同步,互斥,终止和挂起等等控制信息的传递)
  2. 高级通信,大批数据信息的通信(主要用于进程间数据块数据的交换和共享,常见的高级通信有管道,消息队列,共享内存等).

  3. 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。

  4. 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
  5. 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。不是用于交换大批数据,而用于多线程之间的同步.常作为一种锁机制,防止某进程在访问资源时其它进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
  6. 消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
  7. 信号 ( signal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
  8. [共享内存( shared memory )] :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
  9. 套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。

本文摘自: 线程间的通信、同步方式与进程间通信方式

欢迎加入PHP交流群(QQ群号):PHP编程技术交流群 440221268

欢迎加入Golang交流群(QQ群号):PHP/Golang技术交流群 423069874

results matching ""

    No results matching ""