進(jìn)程和線程的區(qū)別及通信方式

程序只是一組指令的有序集合,它本身沒有任何運(yùn)行的含義,它只是一個靜態(tài)的實體。而進(jìn)程則不同,它是程序在某個數(shù)據(jù)集上的執(zhí)行。進(jìn)程是一個動態(tài)的實體,它有自己的生命周期。它因創(chuàng)建而產(chǎn)生,因調(diào)度而運(yùn)行,因等待資源或事件而被處于等待狀態(tài),因完成任務(wù)而被撤消。反映了一個程序在一定的數(shù)據(jù)集上運(yùn)行的全部動態(tài)過程。

進(jìn)程:是并發(fā)執(zhí)行的程序在執(zhí)行過程中分配和管理資源的基本單位,是一個動態(tài)概念,競爭計算機(jī)系統(tǒng)資源的基本單位。

線程:是進(jìn)程的一個執(zhí)行單元,是進(jìn)程內(nèi)科調(diào)度實體。比進(jìn)程更小的獨(dú)立運(yùn)行的基本單位。線程也被稱為輕量級進(jìn)程。

一個程序至少一個進(jìn)程,一個進(jìn)程至少一個線程。

為什么會有線程?

每個進(jìn)程都有自己的地址空間,即進(jìn)程空間,在網(wǎng)絡(luò)或多用戶換機(jī)下,一個服務(wù)器通常需要接收大量不確定數(shù)量用戶的并發(fā)請求,為每一個請求都創(chuàng)建一個進(jìn)程顯然行不通(系統(tǒng)開銷大響應(yīng)用戶請求效率低),因此操作系統(tǒng)中線程概念被引進(jìn)。

線程的執(zhí)行過程是線性的,盡管中間會發(fā)生中斷或者暫停,但是進(jìn)程所擁有的資源只為改線狀執(zhí)行過程服務(wù),一旦發(fā)生線程切換,這些資源需要被保護(hù)起來。
進(jìn)程分為單線程進(jìn)程和多線程進(jìn)程,單線程進(jìn)程宏觀來看也是線性執(zhí)行過程,微觀上只有單一的執(zhí)行過程。多線程進(jìn)程宏觀是線性的,微觀上多個執(zhí)行操作。
線程的改變只代表CPU的執(zhí)行過程的改變,而沒有發(fā)生進(jìn)程所擁有的資源的變化。

進(jìn)程線程的區(qū)別:

地址空間:同一進(jìn)程的線程共享本進(jìn)程的地址空間,而進(jìn)程之間則是獨(dú)立的地址空間。
資源擁有:同一進(jìn)程內(nèi)的線程共享本進(jìn)程的資源如內(nèi)存、I/O、cpu等,但是進(jìn)程之間的資源是獨(dú)立的。
     一個進(jìn)程崩潰后,在保護(hù)模式下不會對其他進(jìn)程產(chǎn)生影響,但是一個線程崩潰整個進(jìn)程都死掉。

所以多進(jìn)程要比多線程健壯。

進(jìn)程切換時,消耗的資源大,效率高。所以涉及到頻繁的切換時,使用線程要好于進(jìn)程。同樣如果要求同時進(jìn)行并且又要共享某些變量的并發(fā)操作,只能用線程不能用進(jìn)程

執(zhí)行過程:每個獨(dú)立的進(jìn)程程有一個程序運(yùn)行的入口、順序執(zhí)行序列和程序入口。但是線程不能獨(dú)立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個線程執(zhí)行控制。
線程是處理器調(diào)度的基本單位,但是進(jìn)程不是。
兩者均可并發(fā)執(zhí)行。

優(yōu)缺點(diǎn):

線程執(zhí)行開銷小,但是不利于資源的管理和保護(hù)。線程適合在SMP機(jī)器(雙CPU系統(tǒng))上運(yùn)行。

進(jìn)程執(zhí)行開銷大,但是能夠很好的進(jìn)行資源管理和保護(hù)。進(jìn)程可以跨機(jī)器前移。

何時使用多進(jìn)程,何時使用多線程?

對資源的管理和保護(hù)要求高,不限制開銷和效率時,使用多進(jìn)程。

要求效率高,頻繁切換時,資源的保護(hù)管理要求不是很高時,使用多線程。


進(jìn)程間通信

多進(jìn)程:

首先,先來講一下fork之后,發(fā)生了什么事情。由fork創(chuàng)建的新進(jìn)程被稱為子進(jìn)程(child process)。該函數(shù)被調(diào)用一次,但返回兩次。兩次返回的區(qū)別是子進(jìn)程的返回值是0,而父進(jìn)程的返回值則是新進(jìn)程(子進(jìn)程)的進(jìn)程 id。將子進(jìn)程id返回給父進(jìn)程的理由是:因為一個進(jìn)程的子進(jìn)程可以多于一個,沒有一個函數(shù)使一個進(jìn)程可以獲得其所有子進(jìn)程的進(jìn)程id。對子進(jìn)程來說,之所以fork返回0給它,是因為它隨時可以調(diào)用getpid()來獲取自己的pid;也可以調(diào)用getppid()來獲取父進(jìn)程的id。(進(jìn)程id 0總是由交換進(jìn)程使用,所以一個子進(jìn)程的進(jìn)程id不可能為0 )。
fork之后,操作系統(tǒng)會復(fù)制一個與父進(jìn)程完全相同的子進(jìn)程,雖說是父子關(guān)系,但是在操作系統(tǒng)看來,他們更像兄弟關(guān)系,這2個進(jìn)程共享代碼空間,但是數(shù)據(jù)空間是互相獨(dú)立的,子進(jìn)程數(shù)據(jù)空間中的內(nèi)容是父進(jìn)程的完整拷貝,指令指針也完全相同,子進(jìn)程擁有父進(jìn)程當(dāng)前運(yùn)行到的位置(兩進(jìn)程的程序計數(shù)器pc值相同,也就是說,子進(jìn)程是從fork返回處開始執(zhí)行的),但有一點(diǎn)不同,如果fork成功,子進(jìn)程中fork的返回值是0,父進(jìn)程中fork的返回值是子進(jìn)程的進(jìn)程號,如果fork不成功,父進(jìn)程會返回錯誤。
可以這樣想象,2個進(jìn)程一直同時運(yùn)行,而且步調(diào)一致,在fork之后,他們分別作不同的工作,也就是分岔了。這也是fork為什么叫fork的原因。至于那一個最先運(yùn)行,可能與操作系統(tǒng)(調(diào)度算法)有關(guān),而且這個問題在實際應(yīng)用中并不重要,如果需要父子進(jìn)程協(xié)同,可以通過原語的辦法解決。


進(jìn)程常見的通信方式:

  1. 管道pipe:管道是一種半雙工的通信方式,數(shù)據(jù)只能單向流動,而且只能在具有親緣關(guān)系的進(jìn)程間使用。進(jìn)程的親緣關(guān)系通常是指父子進(jìn)程關(guān)系。
  2. 命名管道FIFO:有名管道也是半雙工的通信方式,但是它允許無親緣關(guān)系進(jìn)程間的通信。
  3. 消息隊列MessageQueue:消息隊列是由消息的鏈表,存放在內(nèi)核中并由消息隊列標(biāo)識符標(biāo)識。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節(jié)流以及緩沖區(qū)大小受限等缺點(diǎn)。
  4. 共享存儲SharedMemory:共享內(nèi)存就是映射一段能被其他進(jìn)程所訪問的內(nèi)存,這段共享內(nèi)存由一個進(jìn)程創(chuàng)建,但多個進(jìn)程都可以訪問。共享內(nèi)存是最快的 IPC 方式,它是針對其他進(jìn)程間通信方式運(yùn)行效率低而專門設(shè)計的。它往往與其他通信機(jī)制,如信號兩,配合使用,來實現(xiàn)進(jìn)程間的同步和通信。
  5. 信號量Semaphore:信號量是一個計數(shù)器,可以用來控制多個進(jìn)程對共享資源的訪問。它常作為一種鎖機(jī)制,防止某進(jìn)程正在訪問共享資源時,其他進(jìn)程也訪問該資源。因此,主要作為進(jìn)程間以及同一進(jìn)程內(nèi)不同線程之間的同步手段。
  6. 套接字Socket:套解口也是一種進(jìn)程間通信機(jī)制,與其他通信機(jī)制不同的是,它可用于不同及其間的進(jìn)程通信。
  7. 信號 ( sinal ) : 信號是一種比較復(fù)雜的通信方式,用于通知接收進(jìn)程某個事件已經(jīng)發(fā)生。

詳細(xì)介紹 https://www.cnblogs.com/LUO77/p/5816326.html


線程間通信

一:兩個進(jìn)程間的兩個線程通信,相當(dāng)于進(jìn)程間通信

二:一個進(jìn)程中的兩個線程間通信

通信方式:

1.互斥鎖

mutex;

lock_guard (在構(gòu)造函數(shù)里加鎖,在析構(gòu)函數(shù)里解鎖)

unique_lock 自動加鎖、解鎖

2.讀寫鎖

shared_lock

3.信號量

c++11中未實現(xiàn),可以自己使用mutex和conditon_variable 實現(xiàn)

代碼實現(xiàn)如下:

#pragma once
#include <mutex>
#include <condition_variable>
class Semaphore
{
public:
 explicit Semaphore(unsigned int count); //用無符號數(shù)表示信號量資源 
 ~Semaphore();
public:
 void wait();
 void signal();
private:
 int m_count; //計數(shù)器必須是有符號數(shù) 
 std::mutex m_mutex;
 std::condition_variable m_condition_variable;
};
 
#include "Semaphore.h"
Semaphore::Semaphore(unsigned int count) :m_count(count) {
}
Semaphore::~Semaphore()
{
}
void Semaphore::wait() {
 std::unique_lock<std::mutex> unique_lock(m_mutex);
 --m_count;
 while (m_count < 0) {
  m_condition_variable.wait(unique_lock);
 }
}
void Semaphore::signal() {
 std::lock_guard<std::mutex> lg(m_mutex);
 if (++m_count < 1) {
  m_condition_variable.notify_one();
 }
}

4.條件變量
condition_variable

轉(zhuǎn)自 https://www.cnblogs.com/jobs1/p/10784021.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容