一:進程和線程
每個進程有自己獨立的地址空間。「在同一個進程」還是「不在同一個進程」是系統功能劃分的重要決策點。《Erlang程序設計》[ERL]把進程比喻為人:
每個人有自己的記憶(內存),人與人通過談話(消息傳遞)來交流,談話既可以是面談(同一台伺服器),也可以在電話里談(不同的伺服器,有網路通信)。面談和電話談的區別在於,面談可以立即知道對方是否死了(crash,SIGCHLD),而電話談只能通過周期性的心跳來判斷對方是否還活著。
有了這些比喻,設計分布式系統時可以採取「角色扮演」,團隊里的幾個人各自扮演一個進程,人的角色由進程的代碼決定(管登錄的、管消息分發的、管買賣的等等)。每個人有自己的記憶,但不知道別人的記憶,要想知道別人的看法,只能通過交談(暫不考慮共享內存這種IPC)。然後就可以思考:
·容錯:萬一有人突然死了
·擴容:新人中途加進來
·負載均衡:把甲的活兒挪給乙做
·退休:甲要修復bug,先別派新任務,等他做完手上的事情就把他重啟
等等各種場景,十分便利。
線程的特點是共享地址空間,從而可以高效地共享數據。一台機器上的多個進程能高效地共享代碼段(操作系統可以映射為同樣的物理內存),但不能共享數據。如果多個進程大量共享內存,等於是把多進程程序當成多線程來寫,掩耳盜鈴。
「多線程」的價值,我認為是為了更好地發揮多核處理器(multi-cores)的效能。在單核時代,多線程沒有多大價值(個人想法:如果要完成的任務是CPU密集型的,那多線程沒有優勢,甚至因為線程切換的開銷,多線程反而更慢;如果要完成的任務既有CPU計算,又有磁碟或網路IO,則使用多線程的好處是,當某個線程因為IO而阻塞時,OS可以調度其他線程執行,雖然效率確實要比任務的順序執行效率要高,然而,這種類型的任務,可以通過單線程的」non-blocking IO+IO multiplexing」的模型(事件驅動)來提高效率,採用多線程的方式,帶來的可能僅僅是編程上的簡單而已)。Alan Cox說過:」A computer is a state machine.Threads are for people who can』t program state machines.」(計算機是一台狀態機。線程是給那些不能編寫狀態機程序的人准備的)如果只有一塊CPU、一個執行單元,那麼確實如Alan Cox所說,按狀態機的思路去寫程序是最高效的。
二:單線程伺服器的常用編程模型
據我了解,在高性能的網路程序中,使用得最為廣泛的恐怕要數」non-blocking IO + IO multiplexing」這種模型,即Reactor模式。
在」non-blocking IO + IO multiplexing」這種模型中,程序的基本結構是一個事件循環(event loop),以事件驅動(event-driven)和事件回調的方式實現業務邏輯:
[cpp] view plain
//代碼僅為示意,沒有完整考慮各種情況
while(!done)
{
int timeout_ms = max(1000, getNextTimedCallback());
int retval = poll(fds, nfds, timeout_ms);
if (retval<0){
處理錯誤,回調用戶的error handler
}else{
處理到期的timers,回調用戶的timer handler
if(retval>0){
處理IO事件,回調用戶的IO event handler
}
}
}
這里select(2)/poll(2)有伸縮性方面的不足(描述符過多時,效率較低),Linux下可替換為epoll(4),其他操作系統也有對應的高性能替代品。
Reactor模型的優點很明顯,編程不難,效率也不錯。不僅可以用於讀寫socket,連接的建立(connect(2)/accept(2)),甚至DNS解析都可以用非阻塞方式進行,以提高並發度和吞吐量(throughput),對於IO密集的應用是個不錯的選擇。lighttpd就是這樣,它內部的fdevent結構十分精妙,值得學習。
基於事件驅動的編程模型也有其本質的缺點,它要求事件回調函數必須是非阻塞的。對於涉及網路IO的請求響應式協議,它容易割裂業務邏輯,使其散布於多個回調函數之中,相對不容易理解和維護。
三:多線程伺服器的常用編程模型
大概有這么幾種:
a:每個請求創建一個線程,使用阻塞式IO操作。在Java 1.4引人NIO之前,這是Java網路編程的推薦做法。可惜伸縮性不佳(請求太多時,操作系統創建不了這許多線程)。
b:使用線程池,同樣使用阻塞式IO操作。與第1種相比,這是提高性能的措施。
c:使用non-blocking IO + IO multiplexing。即Java NIO的方式。
d:Leader/Follower等高級模式。
在默認情況下,我會使用第3種,即non-blocking IO + one loop per thread模式來編寫多線程C++網路服務程序。
1:one loop per thread
此種模型下,程序里的每個IO線程有一個event loop,用於處理讀寫和定時事件(無論周期性的還是單次的)。代碼框架跟「單線程伺服器的常用編程模型」一節中的一樣。
libev的作者說:
One loop per thread is usually a good model. Doing this is almost never wrong, some times a better-performance model exists, but it is always a good start.
這種方式的好處是:
a:線程數目基本固定,可以在程序啟動的時候設置,不會頻繁創建與銷毀。
b:可以很方便地在線程間調配負載。
c:IO事件發生的線程是固定的,同一個TCP連接不必考慮事件並發。
Event loop代表了線程的主循環,需要讓哪個線程幹活,就把timer或IO channel(如TCP連接)注冊到哪個線程的loop里即可:對實時性有要求的connection可以單獨用一個線程;數據量大的connection可以獨佔一個線程,並把數據處理任務分攤到另幾個計算線程中(用線程池);其他次要的輔助性connections可以共享一個線程。
比如,在dbproxy中,一個線程用於專門處理客戶端發來的管理命令;一個線程用於處理客戶端發來的MySQL命令,而與後端資料庫通信執行該命令時,是將該任務分配給所有事件線程處理的。
對於non-trivial(有一定規模)的服務端程序,一般會採用non-blocking IO + IO multiplexing,每個connection/acceptor都會注冊到某個event loop上,程序里有多個event loop,每個線程至多有一個event loop。
多線程程序對event loop提出了更高的要求,那就是「線程安全」。要允許一個線程往別的線程的loop里塞東西,這個loop必須得是線程安全的。
在dbproxy中,線程向其他線程分發任務,是通過管道和隊列實現的。比如主線程accept到連接後,將表示該連接的結構放入隊列,並向管道中寫入一個位元組。計算線程在自己的event loop中注冊管道的讀事件,一旦有數據可讀,就嘗試從隊列中取任務。
2:線程池
不過,對於沒有IO而光有計算任務的線程,使用event loop有點浪費。可以使用一種補充方案,即用blocking queue實現的任務隊列:
[cpp] view plain
typedef boost::function<void()>Functor;
BlockingQueue<Functor> taskQueue; //線程安全的全局阻塞隊列
//計算線程
void workerThread()
{
while (running) //running變數是個全局標志
{
Functor task = taskQueue.take(); //this blocks
task(); //在產品代碼中需要考慮異常處理
}
}
// 創建容量(並發數)為N的線程池
int N = num_of_computing_threads;
for (int i = 0; i < N; ++i)
{
create_thread(&workerThread); //啟動線程
}
//向任務隊列中追加任務
Foo foo; //Foo有calc()成員函數
boost::function<void()> task = boost::bind(&Foo::calc,&foo);
taskQueue.post(task);
除了任務隊列,還可以用BlockingQueue<T>實現數據的生產者消費者隊列,即T是數據類型而非函數對象,queue的消費者從中拿到數據進行處理。其實本質上是一樣的。
3:總結
總結而言,我推薦的C++多線程服務端編程模式為:one (event) loop per thread + thread pool:
event loop用作IO multiplexing,配合non-blockingIO和定時器;
thread pool用來做計算,具體可以是任務隊列或生產者消費者隊列。
以這種方式寫伺服器程序,需要一個優質的基於Reactor模式的網路庫來支撐,muo正是這樣的網路庫。比如dbproxy使用的是libevent。
程序里具體用幾個loop、線程池的大小等參數需要根據應用來設定,基本的原則是「阻抗匹配」(解釋見下),使得CPU和IO都能高效地運作。所謂阻抗匹配原則:
如果池中線程在執行任務時,密集計算所佔的時間比重為 P (0 < P <= 1),而系統一共有 C 個 CPU,為了讓這 C 個 CPU 跑滿而又不過載,線程池大小的經驗公式 T = C/P。(T 是個 hint,考慮到 P 值的估計不是很准確,T 的最佳值可以上下浮動 50%)
以後我再講這個經驗公式是怎麼來的,先驗證邊界條件的正確性。
假設 C = 8,P = 1.0,線程池的任務完全是密集計算,那麼T = 8。只要 8 個活動線程就能讓 8 個 CPU 飽和,再多也沒用,因為 CPU 資源已經耗光了。
假設 C = 8,P = 0.5,線程池的任務有一半是計算,有一半等在 IO 上,那麼T = 16。考慮操作系統能靈活合理地調度 sleeping/writing/running 線程,那麼大概 16 個「50%繁忙的線程」能讓 8 個 CPU 忙個不停。啟動更多的線程並不能提高吞吐量,反而因為增加上下文切換的開銷而降低性能。
如果 P < 0.2,這個公式就不適用了,T 可以取一個固定值,比如 5*C。
另外,公式里的 C 不一定是 CPU 總數,可以是「分配給這項任務的 CPU 數目」,比如在 8 核機器上分出 4 個核來做一項任務,那麼 C=4。
四:進程間通信只用TCP
Linux下進程間通信的方式有:匿名管道(pipe)、具名管道(FIFO)、POSIX消息隊列、共享內存、信號(signals),以及Socket。同步原語有互斥器(mutex)、條件變數(condition variable)、讀寫鎖(reader-writer lock)、文件鎖(record locking)、信號量(semaphore)等等。
進程間通信我首選Sockets(主要指TCP,我沒有用過UDP,也不考慮Unix domain協議)。其好處在於:
可以跨主機,具有伸縮性。反正都是多進程了,如果一台機器的處理能力不夠,很自然地就能用多台機器來處理。把進程分散到同一區域網的多台機器上,程序改改host:port配置就能繼續用;
TCP sockets和pipe都是操作文件描述符,用來收發位元組流,都可以read/write/fcntl/select/poll等。不同的是,TCP是雙向的,Linux的pipe是單向的,進程間雙向通信還得開兩個文件描述符,不方便;而且進程要有父子關系才能用pipe,這些都限制了pipe的使用;
TCP port由一個進程獨占,且進程退出時操作系統會自動回收文件描述符。因此即使程序意外退出,也不會給系統留下垃圾,程序重啟之後能比較容易地恢復,而不需要重啟操作系統(用跨進程的mutex就有這個風險);而且,port是獨占的,可以防止程序重復啟動,後面那個進程搶不到port,自然就沒法初始化了,避免造成意料之外的結果;
與其他IPC相比,TCP協議的一個天生的好處是「可記錄、可重現」。tcpmp和Wireshark是解決兩個進程間協議和狀態爭端的好幫手,也是性能(吞吐量、延遲)分析的利器。我們可以藉此編寫分布式程序的自動化回歸測試。也可以用tcp之類的工具進行壓力測試。TCP還能跨語言,服務端和客戶端不必使用同一種語言。
分布式系統的軟體設計和功能劃分一般應該以「進程」為單位。從宏觀上看,一個分布式系統是由運行在多台機器上的多個進程組成的,進程之間採用TCP長連接通信。
使用TCP長連接的好處有兩點:一是容易定位分布式系統中的服務之間的依賴關系。只要在機器上運行netstat -tpna|grep <port>就能立刻列出用到某服務的客戶端地址(Foreign Address列),然後在客戶端的機器上用netstat或lsof命令找出是哪個進程發起的連接。TCP短連接和UDP則不具備這一特性。二是通過接收和發送隊列的長度也較容易定位網路或程序故障。在正常運行的時候,netstat列印的Recv-Q和Send-Q都應該接近0,或者在0附近擺動。如果Recv-Q保持不變或持續增加,則通常意味著服務進程的處理速度變慢,可能發生了死鎖或阻塞。如果Send-Q保持不變或持續增加,有可能是對方伺服器太忙、來不及處理,也有可能是網路中間某個路由器或交換機故障造成丟包,甚至對方伺服器掉線,這些因素都可能表現為數據發送不出去。通過持續監控Recv-Q和Send-Q就能及早預警性能或可用性故障。以下是服務端線程阻塞造成Recv-Q和客戶端Send-Q激增的例子:
[cpp] view plain
$netstat -tn
Proto Recv-Q Send-Q Local Address Foreign
tcp 78393 0 10.0.0.10:2000 10.0.0.10:39748 #服務端連接
tcp 0 132608 10.0.0.10:39748 10.0.0.10:2000 #客戶端連接
tcp 0 52 10.0.0.10:22 10.0.0.4:55572
五:多線程伺服器的適用場合
如果要在一台多核機器上提供一種服務或執行一個任務,可用的模式有:
a:運行一個單線程的進程;
b:運行一個多線程的進程;
c:運行多個單線程的進程;
d:運行多個多線程的進程;
考慮這樣的場景:如果使用速率為50MB/s的數據壓縮庫,進程創建銷毀的開銷是800微秒,線程創建銷毀的開銷是50微秒。如何執行壓縮任務?
如果要偶爾壓縮1GB的文本文件,預計運行時間是20s,那麼起一個進程去做是合理的,因為進程啟動和銷毀的開銷遠遠小於實際任務的耗時。
如果要經常壓縮500kB的文本數據,預計運行時間是10ms,那麼每次都起進程 似乎有點浪費了,可以每次單獨起一個線程去做。
如果要頻繁壓縮10kB的文本數據,預計運行時間是200微秒,那麼每次起線程似 乎也很浪費,不如直接在當前線程搞定。也可以用一個線程池,每次把壓縮任務交給線程池,避免阻塞當前線程(特別要避免阻塞IO線程)。
由此可見,多線程並不是萬靈丹(silver bullet)。
1:必須使用單線程的場合
據我所知,有兩種場合必須使用單線程:
a:程序可能會fork(2);
實際編程中,應該保證只有單線程程序能進行fork(2)。多線程程序不是不能調用fork(2),而是這么做會遇到很多麻煩:
fork一般不能在多線程程序中調用,因為Linux的fork只克隆當前線程的thread of control,不可隆其他線程。fork之後,除了當前線程之外,其他線程都消失了。
這就造成一種危險的局面。其他線程可能正好處於臨界區之內,持有了某個鎖,而它突然死亡,再也沒有機會去解鎖了。此時如果子進程試圖再對同一個mutex加鎖,就會立即死鎖。因此,fork之後,子進程就相當於處於signal handler之中(因為不知道調用fork時,父進程中的線程此時正在調用什麼函數,這和信號發生時的場景一樣),你不能調用線程安全的函數(除非它是可重入的),而只能調用非同步信號安全的函數。比如,fork之後,子進程不能調用:
malloc,因為malloc在訪問全局狀態時幾乎肯定會加鎖;
任何可能分配或釋放內存的函數,比如snprintf;
任何Pthreads函數;
printf系列函數,因為其他線程可能恰好持有stdout/stderr的鎖;
除了man 7 signal中明確列出的信號安全函數之外的任何函數。
因此,多線程中調用fork,唯一安全的做法是fork之後,立即調用exec執行另一個程序,徹底隔斷子進程與父進程的聯系。
在多線程環境中調用fork,產生子進程後。子進程內部只存在一個線程,也就是父進程中調用fork的線程的副本。
使用fork創建子進程時,子進程通過繼承整個地址空間的副本,也從父進程那裡繼承了所有互斥量、讀寫鎖和條件變數的狀態。如果父進程中的某個線程佔有鎖,則子進程同樣佔有這些鎖。問題是子進程並不包含佔有鎖的線程的副本,所以子進程沒有辦法知道它佔有了哪些鎖,並且需要釋放哪些鎖。
盡管Pthread提供了pthread_atfork函數試圖繞過這樣的問題,但是這回使得代碼變得混亂。因此《Programming With Posix Threads》一書的作者說:」Avoid using fork in threaded code except where the child process will immediately exec a new program.」。
b:限製程序的CPU佔用率;
這個很容易理解,比如在一個8核的伺服器上,一個單線程程序即便發生busy-wait,占滿1個core,其CPU使用率也只有12.5%,在這種最壞的情況下,系統還是有87.5%的計算資源可供其他服務進程使用。
因此對於一些輔助性的程序,如果它必須和主要服務進程運行在同一台機器的話,那麼做成單線程的能避免過分搶奪系統的計算資源。
Ⅱ Linux有哪些優缺點
優點是:
1、開放性:linux操作系統遵守GNU規范,代碼共享,易於實現系統的裁剪和客制化的開發。
2、多用戶:系統資源可以被不同用戶以各自的許可權訪問使用,互不影響。
3、多任務和多線程:不同任務和線程幾乎同時並發地處理獨立的但卻內在關聯的一系列事件
4、設備獨立性:linux操作系度統把所有外部設備統一當作設備文件來看待,只要安裝它們的驅動程序,任何用戶都可以像使用普通文件一知樣,操縱、使用這些設備,而不必知道它們的具體存在形式。
5、豐富的網路功能:完善的內置網路是Linux的一大特點。
缺點是:
主要來自於硬體方面的支持,還有就是對於普通用戶來說,它的操作性沒有windows那麼方便,實用,一般用戶使用起來 不太會操作。
Ⅲ linux 下 進程和線程的區別
線程是指進程內的一個執行單元,也是進程內的可調度實體.
與進程的區別:
(1)地址空間:進程內的一個執行單元;進程至少有一個線程;它們共享進程的地址空間;而進程有自己獨立的地址空間;
(2)資源擁有:進程是資源分配和擁有的單位,同一個進程內的線程共享進程的資源
(3)線程是處理器調度的基本單位,但進程不是.
4)二者均可並發執行.
進程和線程都是由操作系統所體會的程序運行的基本單元,系統利用該基本單元實現系統對應用的並發性。進程是系統進行資源分配和調度的一個獨立單位。線程是進程的一個實體,是CPU調度和分派的基本單位,線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源。一個線程可以創建和撤銷另一個線程,同一個進程中的多個線程之間可以並發執行。
2.進程和應用程序的區別?
進程與應用程序的區別在於應用程序作為一個靜態文件存儲在計算機系統的硬碟等存儲空間中,而進程則是處於動態條件下由操作系統維護的系統資源管理實體。
C、C++、Java等語言編寫的源程序經相應的編譯器編譯成可執行文件後,提交給計算機處理器運行。這時,處在可執行狀態中的應用程序稱為進程。從用戶角度來看,進程是應用程序的一個執行過程。從操作系統核心角度來看,進程代表的是操作系統分配的內存、CPU時間片等資源的基本單位,是為正在運行的程序提供的運行環境。進程與應用程序的區別在於應用程序作為一個靜態文件存儲在計算機系統的硬碟等存儲空間中,而進程則是處於動態條件下由操作系統維護的系統資源管理實體。多任務環境下應用程序進程的主要特點包括: ●進程在執行過程中有內存單元的初始入口點,並且進程存活過程中始終擁有獨立的內存地址空間; ●進程的生存期狀態包括創建、就緒、運行、阻塞和死亡等類型; ●從應用程序進程在執行過程中向CPU發出的運行指令形式不同,可以將進程的狀態分為用戶態和核心態。處於用戶態下的進程執行的是應用程序指令、處於核心態下的應用程序進程執行的是操作系統指令
3.進程與Java線程的區別
應用程序在執行過程中存在一個內存空間的初始入口點地址、一個程序執行過程中的代碼執行序列以及用於標識進程結束的內存出口點地址,在進程執行過程中的每一時間點均有唯一的處理器指令與內存單元地址相對應。
Java語言中定義的線程(Thread)同樣包括一個內存入口點地址、一個出口點地址以及能夠順序執行的代碼序列。但是進程與線程的重要區別在於線程不能夠單獨執行,它必須運行在處於活動狀態的應用程序進程中,因此可以定義線程是程序內部的具有並發性的順序代碼流。 Unix操作系統和Microsoft Windows操作系統支持多用戶、多進程的並發執行,而Java語言支持應用程序進程內部的多個執行線程的並發執行。多線程的意義在於一個應用程序的多個邏輯單元可以並發地執行。但是多線程並不意味著多個用戶進程在執行,操作系統也不把每個線程作為獨立的進程來分配獨立的系統資源。進程可以創建其子進程,子進程與父進程擁有不同的可執行代碼和數據內存空間。而在用於代表應用程序的進程中多個線程共享數據內存空間,但保持每個線程擁有獨立的執行堆棧和程序執行上下文(Context)。
需要注意的是:在應用程序中使用多線程不會增加 CPU 的數據處理能力。只有在多CPU 的計算機或者在網路計算體系結構下,將Java程序劃分為多個並發執行線程後,同時啟動多個線程運行,使不同的線程運行在基於不同處理器的Java虛擬機中,才能提高應用程序的執行效率。 另外,如果應用程序必須等待網路連接或資料庫連接等數據吞吐速度相對較慢的資源時,多線程應用程序是非常有利的。基於Internet的應用程序有必要是多線程類型的,例如,當開發要支持大量客戶機的伺服器端應用程序時,可以將應用程序創建成多線程形式來響應客戶端的連接請求,使每個連接用戶獨佔一個客戶端連接線程。這樣,用戶感覺伺服器只為連接用戶自己服務,從而縮短了伺服器的客戶端響應時間。 三、Java語言的多線程程序設計方法
Ⅳ 在Linux環境下,對一個設備文件進行多線程讀寫(兩個線程就行),求大神給一個簡單的程序。
配置文件為 conf.txt
測試代碼如下,注意鏈接的時候加上 -lpthread 這個參數
#include <stdio.h>
#include <errno.h> //perror()
#include <pthread.h>
#include <unistd.h> //sleep()
#include <time.h> // time()
#include <stdlib.h> //rand()
#define FD "conf.txt"
typedef void *(*fun)(void *);
struct my_struct
{
unsigned time_to_wait;
int n;
};
void *test_thread(struct my_struct *);
int main (int argc, char const *argv[])
{
FILE *fp = fopen(FD, "r");
if (fp == NULL)
{
perror(FD);
return -1;
}
srand((unsigned)time(NULL)); //初始化隨機種子
int thread_count;
fscanf(fp, "%d", &thread_count);
fclose(fp);
if (thread_count <= 0)
{
printf("線程數<1,退出程序。\n");
return -1;
}
pthread_t *ptid = (pthread_t *)malloc(sizeof(pthread_t) * thread_count); //保存線程ID
int i;
for (i = 0; i < thread_count; i++)
{
int tw = rand() % thread_count + 1; //隨機等待時間
struct my_struct * p = (struct my_struct *)malloc(sizeof(struct my_struct));
if (p == NULL)
{
perror("內存分配錯誤");
goto ERROR;
}
p->time_to_wait = tw;
p->n = i + 1;
int rval = pthread_create(ptid + i, NULL, (fun) test_thread, (void *)(p)); //注意這里的強制轉換(兩個)
if (rval != 0)
{
perror("Thread creation failed");
goto ERROR;
}
//sleep(1); //這句加也可以,不加也可以。最開始的時候加上這個是為了讓兩個線程啟動的時候之間有一定的時間差
}
printf("主線程啟動\n\n");
fflush(stdout);
for (i = 0; i < thread_count; i++)
{
pthread_join(*(ptid + i), NULL); //等待所有線程退出。
}
printf("\n主線程退出\n");
ERROR:
free(ptid);
return 0;
}
void *test_thread(struct my_struct * p) //線程啟動的時候運行的函數
{
printf("第%d個線程啟動,預計運行%d秒\n", p->n, p->time_to_wait);
fflush(stdout);
sleep(p->time_to_wait); //讓線程等待一段時間
printf("第%d個線程結束\n", p->n);
fflush(stdout);
free(p);
return NULL;
}
你的第二個問題我在網路HI回你了~
Ⅳ linux裡面,進程與線程到底有什麼本質的區別
線程:是進程中執行的一條路徑,是系統調度的最小單位。
進程:是正在運行的程序,是系統分配資源的最小單位。
線程與進程關系
1.一個進程可以有多個線程,一個線程只能屬於一個進程。
2.同一個進程下的所有線程共享該進程下的所有資源。
3.真正在處理機上運行的是線程,不是進程,線程是進程內的一個執行單元,是進程內的可調度實體。
Linux線程與進程區別
進程:
優點:多進程可以同時利用多個CPU,能夠同時進行多個操作。
缺點:耗費資源(創建一個進程重新開辟內存空間)。
進程不是越多越好,一般進程個數等於cpu個數。
線程:
優點:共享內存,尤其是進行IO操作(網路、磁碟)的時候(IO操作很少用cpu),可以使用多線程執行並發操作。
缺點:搶占資源。
Ⅵ Linux中進程和線程的對比與區別
線程和進程是另一對有意義的概念,主要區別和聯系如下:
進程是操作系統進行資源分配的基本單位,擁有完整的進程空間。進行系統資源分配的時候,除了CPU資源之外,不會給線程分配獨立的資源,線程所需要的資源需要共享。
線程是進程的一部分,如果沒有進行顯示的線程分配,可以認為進程是單線程的;如果進程中建立了線程,則可認為系統是多線程的。
多線程和多進程是兩種不同的概念。多線程與多進程有不同的資源共享方式。
進程有進程式控制制塊PCB,系統通過PCB對進程進行調度。進程有線程式控制制塊TCP,但TCB所表示的狀態比PCB要少的多。
Ⅶ linux中多個進程公用一個socket的問題
從設計上來說, 設計成多線程比較好,可以實現同時工作 (CUP 使用時間分片機制).至於套節字,分開來使用更簡單,通信雙方也能更好解析信息.如果要考慮共用一個套節字,需要使用互斥機制.
Ⅷ 嵌入式linux和linux有什麼不同.linux的作用是什麼
Linux作為開源免費操作系統,以其作為系統的應用可以較方便的進行系統功能的裁剪和跨體系結構移植。
在不同的目標體系結構下(x86,ARM,PowerPC etc.),由於匯編指令集的不同,同一段代碼利用不同的編譯器和庫文件生成的可執行代碼是不同的。不同體系的Linux其開發工具是不同的。
嵌入式linux屬於高度裁剪過的Linux,他將桌面Linux所具有的大部分應用功能(如GUI 工具,計算器,電子郵件 etc.)和部分系統功能省略,但集成了開發者希望嵌入式產品所具有的特殊應用功能(比如 一款以Linux為系統的觸摸式海事導航儀可以根據功能需要去除不需要的功能塊,但加入GPS定位,航速航向計算,航線規劃,觸摸檢測和對應功能實現等功能)。
嵌入式系統往往是指系統的資源(如DRAM/FLASH ROM,功耗,工作頻率 etc.)有較大限制且系統的工作環境相對多變和惡劣(如溫濕度變化大,酸鹼度腐蝕,外部撞擊和振動,外部電磁干擾,靜電導致的高壓損壞電路 etc.)。這也就需要開發人員更多的發現和假想可能的突發情況並採取相應預防措施。大部分嵌入式系統對響應的時間限制和正確性也有極高的要求。