❶ c語言 阻塞,非阻塞和多線程有什麼關系
阻塞是在傳統的網路編程中我們依賴於ServerSocket,Socket進行通信,大致的框架就是ServerSocket調用accept方法,等待客戶端的連接,如果連接進來的時候則創建一個伺服器端socket,客戶端和伺服器端socket建立好InputStream 和outputStream通道進行通信,在這個網路IO的過程中inputStream的read 和outputStream的write方法都可能發送阻塞。為了減少這種阻塞對其他連接的影響,一般都會在伺服器端為每個連接開辟一個新的線程,或者使用線程池技術來避免線程的創建銷毀同時又一定程度支持並發量。然而這種情況下,如果發生大量的read 或者write阻塞線程池的效率會大大降低,而且操作系統也額外需要頻繁的處理cpu的切換。
非阻塞式通信實際是對上述模式的擴展,它的核心思想是為傳統的socket加入事件監聽的功能,操作系統可以在socket和serversocket上進行事件監聽,一旦監聽的對象發生了連接和可讀可寫的事件,監聽器就會對注冊了事件的對象返回相應的通知。在javaNIO中實現這一套的機制就是把socket 和ServerSocket重寫成為SocketChanel,ServerSocketChanel,他們的底層仍然使用socket實現,所以原則上javaNIO包可以完全實現阻塞和非阻塞兩種編程模式。事件監聽的功能由Selection類完成,他使用select方法一直阻塞式監聽注冊了的事件是否發生,對於每一個發生的事件,他都會返回一個selectionKey,通過這個key我們就可以確定這個事件的發生源(socket)和相關信息。對於ServerSocketChanel,Socketchanel分別對應了不同的事件,serverChanel只有OP_ACCEPT代表是否可以接受連接,而socketChanel則有OP_CONNECT、read、write事件。筆者認為與阻塞IO相比他的優勢在於可以避免read 和write的阻塞,因為這個比較具有實際意義的。比如是一個網路文件傳輸系統,read方法可能會因為網路原因發生多次阻塞,使用非阻塞IO read的話線程可以立即返回去處理其他任務。
多線程是在進程中進一步去劃分的獨立單元。
❷ C# 關於多線程和CPU的問題
1.CPU發展趨勢
核心數目依舊會越來越多,依據摩爾定律,由於單個核心性能提升有著嚴重的瓶頸問題,普通的桌面PC有望在2017年末2018年初達到24核心(或者16核32線程),我們如何來面對這突如其來的核心數目的增加?編程也要與時俱進。筆者斗膽預測,CPU各個核心之間的片內匯流排將會採用4路組相連:),因為全相連太過復雜,單匯流排又不夠給力。而且應該是非對稱多核處理器,可能其中會混雜幾個DSP處理器或流處理器。
2.多線程與並行計算的區別
(1)多線程的作用不只是用作並行計算,他還有很多很有益的作用。
還在單核時代,多線程就有很廣泛的應用,這時候多線程大多用於降低阻塞(意思是類似於
while(1)
{
if(flag==1)
break;
sleep(1);
}
這樣的代碼)帶來的CPU資源閑置,注意這里沒有浪費CPU資源,去掉sleep(1)就是純浪費了。
阻塞在什麼時候發生呢?一般是等待IO操作(磁碟,資料庫,網路等等)。此時如果單線程,CPU會干轉不幹實事(與本程序無關的事情都算不幹實事,因為執行其他程序對我來說沒意義),效率低下(針對這個程序而言),例如一個IO操作要耗時10毫秒,CPU就會被阻塞接近10毫秒,這是何等的浪費啊!要知道CPU是數著納秒過日子的。
所以這種耗時的IO操作就用一個線程Thread去代為執行,創建這個線程的函數(代碼)部分不會被IO操作阻塞,繼續干這個程序中其他的事情,而不是乾等待(或者去執行其他程序)。
同樣在這個單核時代,多線程的這個消除阻塞的作用還可以叫做「並發」,這和並行是有著本質的不同的。並發是「偽並行」,看似並行,而實際上還是一個CPU在執行一切事物,只是切換的太快,我們沒法察覺罷了。例如基於UI的程序(俗話說就是圖形界面),如果你點一個按鈕觸發的事件需要執行10秒鍾,那麼這個程序就會假死,因為程序在忙著執行,沒空搭理用戶的其他操作;而如果你把這個按鈕觸發的函數賦給一個線程,然後啟動線程去執行,那麼程序就不會假死,繼續相應用戶的其他操作。但是,隨之而來的就是線程的互斥和同步、死鎖等問題,詳細見有關文獻。
現在是多核時代了,這種線程的互斥和同步問題是更加嚴峻的,單核時代大都算並發,多核時代真的就大為不同,為什麼呢?具體細節請參考有關文獻。我這里簡單解釋一下,以前volatile型變數的使用可以解決大部分問題,例如多個線程共同訪問一個Flag標志位,如果是單核並發,基本不會出問題(P.S.在什麼情況下會出問題呢?Flag有多個,或者是一個數組,這時候只能通過邏輯手段搞定這個問題了,多來幾次空轉無所謂,別出致命問題就行),因為CPU只有一個,同時訪問這個標志位的只能有一個線程,而多核情況下就不太一樣了,所以僅僅volatile不太能解決問題,這就要用到具體語言,具體環境中的「信號量」了,Mutex,Monitor,Lock等等,這些類都操作了硬體上的「關中斷」,達到「原語」效果,對臨界區的訪問不被打斷的效果,具體就不解釋了,讀者可以看看《現代操作系統》。
(2)並行計算還可以通過其他手段來獲得,而多線程只是其中之一。
其他手段包括:多進程(這又包括共享存儲區的和分布式多機,以及混合式的),指令級並行。
ILP(指令級並行),x86架構里叫SMT(同時多線程),在MIPS架構里與之對應的是super scalar(超標量)和亂序執行,二者有區別,但共同點都是可以達到指令級並行,這是用戶沒法控制的,不屬於編程范圍,只能做些有限的優化,而這有限的優化可能只屬於編譯器管轄的范疇,用戶能做的甚少。
(3)典型的適於並行計算的語言
Erlang和MPI:這兩個前者是語言,後者是C++和Fortran的擴展庫,效果是一樣的,利用多進程實現並行計算,Erlang是共享存儲區的,MPI是混合型的。
C#.NET4.0:新版本4.0可以用少量代碼實現並行For循環,之前版本需要用很繁瑣的代碼才能實現同樣功能。這是利用了多線程實現並行計算。Java和C#3.5都有線程池(ThreadPool),也是不錯的很好用的多線程管理類,可以方便高效的使用多線程。
CUDA,還是個初生牛犢,有很大的發展潛力,只不過就目前其應用領域很有限。其目前只能使用C語言,而且還不是C99,比較低級,不能使用函數指針。個人感覺這由於硬體上天生的局限性(平均每個核心可用內存小,與系統內存通訊時間長),只適用於做科學計算,靜態圖像處理,視頻編碼解碼,其他領域,還不如高端CPU。等以後GPU有操作系統了,能充分調度GPU資源了,GPU就可以當大神了。游戲中的物理加速,實際上多核CPU也能很好的做到。
❸ c語言線程池關於空閑線程隊列的疑問
沒錯,沒有這些隊列照樣可以做線程池,只是有了這些隊列可以控制一下每個工作線程的負載
❹ C語言如何使用線程池中的某個線程
問別人問題,還這么牛叉,真心佩服
不要給線程派任務,讓線程空閑的時候,自己去領任務
❺ epoll可以解決多個socket的連接,為什麼高並發伺服器還要用進程池或者線程池呢
socket接受線程:C語言為了高並發所以選擇了epoll。當程序啟動的時候(g_net_update.c文件中main函數,會啟動一個thread見函數create_accept_task)這個thread就處理一件事情,只管接收客戶端的連接,當有連接進來的時候 通過epoll_ctl函數,把socket fd 加入到epoll裡面去,epoll設置監聽事件EPOLLIN | EPOLLET; 主要是監聽的是加入到epoll中的socket是否可讀(因為我的需求是客戶端連上了server就會馬上向server發送一份數據的)。其它的部分在主線程中處理。
主線程:是一個無線循環,epoll_wait 函數相當於把客戶端的連接從epoll中拿出來(因為我們監聽的是EPOLLIN | EPOLLET)說明這個時候客戶端有數據發送過來)。再通過recv_buffer_from_fd 函數把客戶端發送過來的數據讀出來。然後其他的一切就拋給線程池去處理。
線程池:(代碼中我會在池裡面創建15個線程) 雙向鏈表。加入線程就是在鏈表後面加一個鏈表項,鏈表的前面會一個一個被拿出來處理。主要是malloc 函數free函數,sem_wait函數sem_post的處理(sem_wait 會阻塞當值大於0是會減一,sem_post是值加一)。typedef void* (FUNC)(voidarg, int index);是我們自定義的線程的邏輯處理部分,arg是參數,index是第幾個線程處理(我們隱形的給每個線程都標了號),例如代碼中的respons_stb_info,更加具體可以看看代碼裡面是怎麼實現的。聰明的你也可以改掉這塊的內容改成動態線程池,當某個時刻的處理比較多的時候能夠動態的增加線程,而不像我代碼裡面的是固定的。
資料庫連接池:按照我的需求在處理客戶端請求數據的時候是要訪問資料庫的。就是一下子創建出一堆的數據連接。要訪問資料庫的時候先去資料庫連接池中找出空閑的連接,具體可以看下代碼。使用的時候可以參考下database_process.c文件(代碼中資料庫連接池和線程池中的個數是一樣的)。這里我想說下get_db_connect_from_pool這個函數,我用了隨機數,我是為了不想每次都從0開始去判斷哪個連接沒有用到。為了資料庫連接池中的每個鏈接都能等概率的使用到,具體的還是可以看下代碼的實現。