王立靜 馮劍炳
摘 要
大多數客戶端軟件都能夠并發運行,那是由于底層的OS允許用戶并發地運行及操作各個客戶端軟件,或者是由于多臺PC上的用戶在同一時間獨自運行客戶端軟件。單獨一個客戶端軟件就相當于普通的程序那樣運行;它不明顯地管理并發。并發提供了很多蘊藏在C/S交互背后的能力,但隨之帶來的問題卻是使軟件的設計和構建變得更加的困難。
【關鍵詞】并發運行 服務器 切換 進程
1 服務器與網絡中的并發
與并發的客戶端軟件截然不同的是,實現服務器中的并發需要浪費不少的時間。單個服務器必須并發地處理多個傳入的請求(incoming request)。比如,有那么一個遠程登錄的服務器,這臺服務器并不能并發運行,而是每次只能接受一臺客戶機的遠程登錄。那么當有一個客戶機與其建立了遠程關系后,服務器就只能忽略或者直接拒絕其他客戶機的連接請求,直到第一個客戶機用戶的結束或釋放會話。很明顯,這樣的設計限制了服務器使用,從而使多個遠程用戶不能在同一時間訪問某臺主機。
分布式計算機的基礎就是并發處理,并發會以不同形式出現。并發的產生可以是在單個網絡中的各個主機之間,許多成對的應用程序可以進行并發通信,共享它們之間的互連網絡,但它們的應該進程看上去卻像是獨立地運行一樣;也可以在特定的計算機系統中,比如一個用戶正在游覽網頁,而另一個用戶又進行著遠程的操作,從用戶表面看,就像所有的客戶程序同時都在運行中;還可以在一組主機上的所有客戶端之間進行并發執行。程序員并不用在客戶軟件的并發中特別浪費時間。因為操作系統允許多個用戶在同一時間各自運行某個程序,程序間的并發是與生俱有的。所以說各個客戶端程序的運行很像一個個普通的程序。
2 進程在并發處理中的作用
在并發處理的系統中,進程(process)這種抽象定義了計算機的基本任務或者說是基本單元。我們認為一個進程包括一段地址空間和至少一個執行的線程(thread)。線程最重要的信息是一個指令指針(instruction pointer),它指向該進程正在執行的地址。
與程序的靜態版本不同的是,進程是指只包括一個計算的活動執行。當創建一個進程后,操作系統將程序的一個副本放到計算機中,然后啟動一個線程執行這個程序。也就是說并發處理系統允許一個進程中的多個線程或者是多個進程一只的多個線程在“同一時間”執行同一段代碼。當然,在單處理器的結構體系中一個CPU在任一時間點只能執行單一的線程。為了使用戶看上去好像在同時執行多個程序計算,操作系統在所有正在進行操作的線程之間不斷快速的切換CPU計算。這樣從用戶角度看,許多線程像是同時運行的,但其實CPU只能同時處理一個線程,CPU是一個線程執行了一段時間后,再到別一個線程上去執行一段時間,如此快速的反復著。而在多處理器系統中,所有的CPU是可以同時執行多個線程的。
3 進程分離的優勢
雖然說一個進程是可以包含多個執行的線程的,但fork()卻不可以復制這個進程的所有線程。在fork創建一個運行進程副本時,新進程僅含有執行fork()的那個線程。所以,除非程序員明確創建了多個線程,不然每一個進程都是單線程的。
fork是可以用來創建新進程的,它與原來的進程執行完全一樣的代碼,且代碼中的變量值也一模一樣。因為創建的副本與原進程代碼一樣,且又執行完全一樣的計算,那是不是就是說這樣的副本是沒有意思和用處的呢?其實在實際的應用中,fork所創建的進程與原進程其實還是有一些小細節上的不同的。Fork是一個函數,它需要返回值。當函數調用返回進,給原進程的值和返回給新創建進程的值是不同的。新創建的進程時,fork函數的返回值是0;而在原進程中,fork函數返回值則是進程標識符(process identifier)進程或進各id,簡寫pid。并發程序利用fork的返回值來決定如何繼續執行。最常見的是在代碼中判斷返回值是否是0的條件語句。例如:
#include
Int s;
main()
{intpid;
s=0;
pid=fork();
if (pid!=0)
{printf(“在原來的進程中”);}
else
{printf (“在新創建的進程中”);}
exit(0);
}
也就是說在原進程和新創建的進程里,fork函數所返回的值是不同的;并發程序則是利用這個值讓新進程執行與原進程不一樣的代碼。
4 切換和協議軟件的設計
操作系統所提供的并發處理機制使得程序的功能更強大,而且更加容易理解,但它們的確是有計算開銷的。于是,操作系統采用了時間分片機制來保證所有線程的并發執行,在各個線程之間非常快速地切換一個或多個CPU,以至于用戶在使用過程中像是在同時執行。當操作系統暫停一個線程的去切換到別的線程時,會發生切換(switch)。當然,在同一個進程中的多線程間切換的開銷要比不同進程中線程間切換的開銷少一些。但無論如何,線程間的切換都要用到CPU,而且在CPU正忙于切換時,任何線程都是不能保證其服務的。因此,為了減少不必要的開銷,設計協議軟件的時候應想方設法將切換的次數減到最小。特別是程序員需保證在服務器中引入并發處理所帶來的好處比切換的開銷要多。
5 結束語
并發使用戶不必一個等著一個地接受服務。多用戶的并發很容易發生,因為多個戶可以在同一時間執行客戶應用軟件。然后服務器軟件是必須通過編程來并發地處理請求的。并發程序可以利用fork函數的返回值使新創建的進程執行與原進程不同的程序。但并發并非不用付出代價。當操作系統人一個進程切換到另一個進程時,系統就會用到CPU。在服務器設計中要使用并發的程序員應該保證并發設計所帶來的好處要超過由于其切換所引起的開銷。
參考文獻
[1]Douglas Schmidt 編著.并發和聯網對象模式[M].北京:人民郵電出版社,2013(12).
[2]李彬編著.Linux QtGui并發詳解[M].北京:航空航天出版社,2013(02).
[3]Martin Erlang編著.OTP并發編程實戰[M].北京:人民郵電出版社,2012(07).
[4]Joseph Bowbeer編著.Java 并發編程實戰[M].北京:機械工業出版社,2012(02).
作者單位
1.浙江農業商貿職業學院 浙江省紹興市 312000
2.紹興科技館 浙江省紹興市 312000