c++拾遺--多執行緒:c語言多執行緒的引入
多執行緒是程式設計中的乙個重要內容。多核時代使多執行緒成為一種可能,顯然,一件事情多個人幹,效率一定會提公升。下面來看下c語言中是如何使用多執行緒的。
先來看乙個例項
#define _crt_secure_no_warnings
#include #include #include #include dword winapi run(void *p)
int main(void)
; handle handles[3];
for (int i = 0; i < sizeof(mess) / sizeof(*mess); i++)
waitformultipleobjects(3, handles, 1, infinite);
return 0;
}
執行
非同步彈出了三個視窗,並列印了各自的執行緒號。若是有沒看懂的地方,下面有詳細解釋:
1.handle是控制代碼,在windows中用控制代碼來標識物件。本質很簡單 typedef void * handle;
2.createthread()用來建立執行緒。原型
handle winapi createthread(
lpsecurity_attributes lpthreadattributes, //核心物件的安全屬性
size_t dwstacksize, //執行緒棧大小
lpthread_start_routine lpstartaddress, //執行緒函式位址
lpvoid lpparameter, //傳給執行緒函式的引數
dword dwcreationflags, //控制位
lpdword lpthreadid //獲取執行緒id
);引數解釋:
第乙個引數是執行緒核心物件的安全屬性,一般傳入
null
表示使用預設設定。
第二個引數是執行緒棧空間的大小。傳入
0表示使用預設大小(
1mb)。
第三個引數是新執行緒所執行的執行緒函式位址,多個執行緒可以使用同乙個函式位址。
第四個引數是傳給執行緒函式的引數。typedef void * lpvoid
第五個引數是用來控制線程的建立,0表示建立後立即執行。
第六個引數是傳出引數,用來獲得執行緒的id。顯然,傳入null,表示呼叫者並不想知道執行緒的id。
返回值:執行緒控制代碼
3.執行緒函式的宣告。#define winapi __stdcall (vs2013)typedef unsigned long dword。其中,__stdcall是指c/cpp中函式的呼叫方式。主要有兩點:1.實參從右向左入棧。2.呼叫者負責清空引數棧。
4.執行緒等待函式
dword winapi waitformultipleobjects(
dword ncount, //核心物件的個數
const handle *lphandles, //控制代碼陣列的位址
bool bwaitall, //是否等待所有
dword dwmilliseconds //等待的最大時間,單位毫秒,infinite表示無限等待);
函式功能:讓執行緒進入等待轉態,直到條件觸發。核心物件在執行期間處於未觸發的狀態,直到執行結束。
5.執行緒函式型別是
typedef dword (winapi *pthread_start_routine)(lpvoid lpthreadparameter);
更簡潔的是
typedef unsigned long (__stdcall *pfun)(void*);
函式原型
uintptr_t __cdecl _beginthreadex(
void* _security,
unsigned _stacksize,
_beginthreadex_proc_type _startaddress,
void* _arglist,
unsigned _initflag,
unsigned* _thrdaddr
);它的引數型別和createthread基本一致,只是執行緒函式型別稍有不同。執行緒函式型別是
typedef unsigned (__stdcall *_beginthreadex_proc_type)(void*);
createthread的呼叫過於複雜,下面我們玩兒個簡單的,我們用多個執行緒列印 hello world
#include #include #include #include void hello(void *p)
int main()
waitformultipleobjects(5, handles, 1, infinite);
getchar();
return 0;
}
執行
_beginthread的原型
uintptr_t _beginthread(
_beginthread_proc_type _startaddress, //執行緒函式的位址
unsigned _stacksize, //執行緒棧的大小
void* _arglist //執行緒函式的引數);
函式功能:使用指定執行緒函式建立執行緒,並返回執行緒控制代碼。
幾點解釋:
1.typedef unsigned int * uintptr_t;
2.typedef void(__cdecl *_beginthread_proc_type)(void*); _beginthread_proc_type就是一函式指標型別,我們提供的執行緒函式應該如此設計:只有乙個引數,型別為void*,且返回值型別是void。
createthread和_beginthread的使用說明:
從函式引數可以看出,createthread用於對所建立的執行緒進行精細控制。在很多引數處於預設設定下,建議使用引數簡單的_beginthread。
兩者所需的執行緒函式型別不同。
使用多執行緒,就要先寫好執行緒函式,然後呼叫相關函式建立執行緒即可。由於_beginthread傳參簡單,一般情況下,使用_beginthread建立多執行緒。
多個子執行緒對同乙個全域性變數進行操作,容易引起執行緒衝突,也就是子執行緒的互斥問題。
主線程與子執行緒之間的同步問題。
後續文章,會對這兩個問題的解決進行**。
本專欄目錄
所有內容的目錄
多執行緒拾遺 例題
原題 利用多執行緒迴圈列印a b c 思路一 printa printb printc 三個方法,對this加鎖,根據乙個flag來控制列印物件。public class abcre system.out.print a flag b notifyall public synchronized vo...
多執行緒設計拾遺
1 synchronized不能繼承,父類的方法是synchronized,那麼其子類過載方法中就不會繼承 同步 2 構造兩個執行緒之間實時通訊的方法分幾步 1 建立乙個pipedwriter和乙個pipedreader和它們之間的管道 pipedreader in new pipedreader ...
C 拾遺 多執行緒 原子操作解決執行緒衝突
c 拾遺 多執行緒 原子操作解決執行緒衝突 在多執行緒中操作全域性變數一般都會引起執行緒衝突,為了解決執行緒衝突,引入原子操作。include include include include int g count 0 void count void p sleep 100 do some work...