Windows線程使用

1.內(nèi)核對(duì)象

操作系統(tǒng)創(chuàng)建的資源有很多種蘑险,如進(jìn)程、線程岳悟、文件及信號(hào)量佃迄、互斥量等。其中大部分都是通過(guò)程序員的請(qǐng)求創(chuàng)建的贵少,而且請(qǐng)求方式(請(qǐng)求中使用的函數(shù))各不相同呵俏。雖然存在一些差異,但他們之間也有共同點(diǎn):都是由操作系統(tǒng)創(chuàng)建并管理的資源滔灶。

不同資源類型在“管理”方式上也有差異普碎。例如:文件管理中應(yīng)注冊(cè)并更新文件相關(guān)的數(shù)據(jù)I/O位置、文件的打開(kāi)模式等录平。如果是線程麻车,則應(yīng)注冊(cè)并維護(hù)線程ID缀皱、線程所屬進(jìn)程等信息。操作系統(tǒng)為了以記錄相關(guān)信息的方式管理各種資源动猬,在其內(nèi)部生成數(shù)據(jù)塊(可視為結(jié)構(gòu)體變量)啤斗。每種資源需要維護(hù)的信息不同,所以每種資源擁有的數(shù)據(jù)塊格式也有差異赁咙。這類數(shù)據(jù)塊稱為“內(nèi)核對(duì)象”钮莲。

注意:內(nèi)核對(duì)象的所有者是內(nèi)核(操作系統(tǒng)),其含義為:內(nèi)核對(duì)象的創(chuàng)建序目、管理臂痕、銷毀時(shí)機(jī)的決定等工作均由操作系統(tǒng)完成。

2.基于Windows的線程創(chuàng)建

windows創(chuàng)建線程的API原型如下:

#include <windows.h>
HANDLE CreateThread(
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    LPSECURITY_ATTRIBUTES lpThreadAttributes,      // pointer to security attributes  
    DWORD dwStackSize,                             // initial thread stack size  
    LPTHREAD_START_ROUTINE lpStartAddress,         // pointer to thread function  
    LPVOID lpParameter,                            // argument for new thread  
    DWORD dwCreationFlags,                         // creation flags  
    LPDWORD lpThreadId                             // pointer to receive thread ID
);

參數(shù)看起來(lái)有些復(fù)雜猿涨,但只需考慮lpStartAddress和lpParameter這兩個(gè)參數(shù)握童,剩下的傳遞0或NULL即可。

windows線程的銷毀時(shí)間點(diǎn):
windows線程在首次調(diào)用的線程main返回時(shí)銷毀叛赚。還有其它方法可以終止線程澡绩,但最好的辦法就是讓main函數(shù)終止(返回)。

如果線程要調(diào)用C/C++標(biāo)準(zhǔn)函數(shù)俺附,需要通過(guò)如下方法創(chuàng)建線程肥卡。因?yàn)橥ㄟ^(guò)CreateThread函數(shù)調(diào)用創(chuàng)建出的線程在使用C/C++標(biāo)準(zhǔn)函數(shù)時(shí)并不穩(wěn)定。

#include <process.h>  
uintptr_t _beginthreadex(  
    void * security,                     //線程安全相關(guān)信息事镣,使用默認(rèn)設(shè)置時(shí)傳遞NULL  
    unsigned stack_size,                 //要分配給線程的棧大小步鉴,傳遞0時(shí)生成默認(rèn)大小的棧  
    unsigned (* start_address)(void *),  //傳遞線程的main函數(shù)信息  
    void * arglist,                      //調(diào)用main時(shí)傳遞的參數(shù)信息  
    unsigned initflag,                   //用于指定線程創(chuàng)建后的行為,傳遞0時(shí)璃哟,線程創(chuàng)建后立即進(jìn)入可執(zhí)行狀態(tài)  
    unsigned * thrdaddr                  //用于保存線程ID的變量地址值  
    );  
//成功返回線程句柄氛琢,失敗返回0

這個(gè)函數(shù)和CreateThread相比,參數(shù)個(gè)數(shù)以及參數(shù)的含義和順序均相同随闪,只是變量名和參數(shù)類型有所不同阳似。用上面的函數(shù)替換CreateThread時(shí),只需適當(dāng)更改數(shù)據(jù)類型铐伴。

_beginthread函數(shù):
這個(gè)函數(shù)比_beginthreadex更好用撮奏,但該函數(shù)的問(wèn)題在于,它會(huì)讓創(chuàng)建線程時(shí)返回的句柄失效当宴,以防止訪問(wèn)內(nèi)核對(duì)象畜吊。_beginthreadex就是為了解決這一問(wèn)題而定義的函數(shù)。

#include <windows.h>
#include <iostream>
#include <process.h>
unsigned WINAPI ThreadFunc(void *arg);

int main(int argc, char *argv[])
{
    HANDLE hThread;  //線程句柄
    unsigned threadID;  //線程ID
    int param = 5;
    hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (void*)param, 0, &threadID);
    if(0 == hThread)
    {
        std::cout << "_beginthreadex() error" << std::endl;
        return -1;
    }
    Sleep(3000);
    std::cout << "end of main" << std::endl;

    return 0;
}

unsigned WINAPI ThreadFunc(void *arg)
{
    int cnt = *((int*)arg);
    for(int i = 0; i < cnt; i++)
    {
        Sleep(1000);
        std::cout << "running thread" << std::endl;
    }
    return 0;
}

句柄户矢、內(nèi)核對(duì)象和ID間的關(guān)系:
線程也屬于操作系統(tǒng)管理的資源玲献,因此會(huì)伴隨內(nèi)核對(duì)象的創(chuàng)建,并為了引用內(nèi)核對(duì)象而返回句柄。
可以通過(guò)句柄區(qū)分內(nèi)核對(duì)象青自,通過(guò)內(nèi)核對(duì)象區(qū)分線程。最終驱证,線程句柄成為區(qū)分線程的工具延窜。通過(guò)_beginthreadex函數(shù)的最后一個(gè)參數(shù)可以獲取線程ID。句柄和ID有如下顯著特點(diǎn):
句柄的整數(shù)值在不同進(jìn)程中可能出現(xiàn)重復(fù)抹锄,但線程ID在跨進(jìn)范圍內(nèi)不會(huì)重復(fù)逆瑞。

線程ID用于區(qū)分操作系統(tǒng)創(chuàng)建的所有線程,但通常沒(méi)有這種需求伙单。

內(nèi)核對(duì)象的2種狀態(tài):
資源類型不同获高,內(nèi)核對(duì)象也含有不同信息。其中吻育,應(yīng)用程序?qū)崿F(xiàn)過(guò)程中需要特別關(guān)注的信息被賦予某種“狀態(tài)”念秧。例如:線程內(nèi)核對(duì)象中需要重點(diǎn)關(guān)注線程是否已終止,所以終止?fàn)顟B(tài)又稱為“signaled狀態(tài)”布疼,未終止?fàn)顟B(tài)被稱為“non-signaled狀態(tài)”摊趾。

內(nèi)核對(duì)象的狀態(tài)及狀態(tài)查看:
進(jìn)程和線程的內(nèi)核對(duì)象初始狀態(tài)是non-signaled狀態(tài)。內(nèi)核對(duì)象帶有一個(gè)boolean變量游两,其初始值為FALSE砾层,此時(shí)的狀態(tài)就是non-signaled狀態(tài)。如果發(fā)生了事件贱案,把該變量變?yōu)門RUE肛炮,此時(shí)的狀態(tài)就是signaled狀態(tài)。內(nèi)核對(duì)象類型不同宝踪,進(jìn)入signaled的狀態(tài)也有所區(qū)別侨糟。

系統(tǒng)還定義了WaitForSingleObject和WaitForMultipleObjects兩個(gè)函數(shù)。

首先介紹WaitForSingleObject函數(shù),該函數(shù)針對(duì)單個(gè)內(nèi)核對(duì)象驗(yàn)證signaled狀態(tài)逛球。

DWORD WaitForSingleObject(
    HANDLE hHandle,  //handle to object to wait for
    DWORD dwMilliseconds  //time-out interval in milliseconds
);
//返回值:進(jìn)入signaled狀態(tài)返回WAIT_OBJECT_0茫陆,超時(shí)返回WAIT_TIMEOUT

該函數(shù)由于發(fā)生事件(變?yōu)閟ignaled狀態(tài))返回時(shí),有時(shí)會(huì)把相應(yīng)內(nèi)核對(duì)象再次更改為non-signaled狀態(tài)悲幅。這種可以再次進(jìn)入non-signaled狀態(tài)的內(nèi)核對(duì)象稱為“auto-reset模式”的內(nèi)核對(duì)象,而不會(huì)自動(dòng)跳轉(zhuǎn)到non-signaled狀態(tài)的內(nèi)核對(duì)象稱為“manual-reset模式”站蝠。下面的函數(shù)與上述函數(shù)不同汰具,可以驗(yàn)證多個(gè)內(nèi)核對(duì)象狀態(tài)。

DWORD WaitForMultipleObjects(
    DWORD nCount,  // number of handles in the handle array  
    CONST HANDLE *lpHandles,  // pointer to the object-handle array  
    BOOL fWaitAll,  // wait flag  
    DWORD dwMilliseconds  // time-out interval in milliseconds
);

修改后的程序:

    #include <windows.h>  
    #include <iostream>  
    #include <process.h>  
    unsigned WINAPI ThreadFunc(void *arg);  

    int main(int argc, char *argv[])  
    {  
        HANDLE hThread;       //線程句柄  
        DWORD wr;  
        unsigned threadID;    //線程ID  
        int param = 5;  
        hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (void*)param, 0, &threadID);  
        if (0 == hThread)  
        {  
            std::cout << "_beginthreadex() error" << std::endl;  
            return -1;  
        }  

        //傳遞INFINITE時(shí)函數(shù)不會(huì)返回菱魔,直到內(nèi)核對(duì)象變成signaled狀態(tài)  
        if ((wr = WaitForSingleObject(hThread, INFINITE)) == WAIT_FAILED)     
        {  
            std::cout << "thread wait error" << std::endl;  
            return -1;  
        }  
        std::cout << "wait result:" << ((wr == WAIT_OBJECT_0) ? "signed" : "time-out");  
        std::cout << std::endl;  
        std::cout << "end of main" << std::endl;  

        return 0;  
    }  

    unsigned WINAPI ThreadFunc(void *arg)  
    {  
        int cnt = *((int*)arg);  
        for (int i = 0; i < cnt; i++)  
        {  
            Sleep(1000);    
            std::cout << cnt << "running thread" << std::endl;  
        }  
        return 0;  
    }  
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末留荔,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌聚蝶,老刑警劉巖杰妓,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異碘勉,居然都是意外死亡巷挥,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門验靡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)倍宾,“玉大人,你說(shuō)我怎么就攤上這事胜嗓「咧埃” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵辞州,是天一觀的道長(zhǎng)怔锌。 經(jīng)常有香客問(wèn)我,道長(zhǎng)孙技,這世上最難降的妖魔是什么产禾? 我笑而不...
    開(kāi)封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮牵啦,結(jié)果婚禮上亚情,老公的妹妹穿的比我還像新娘。我一直安慰自己哈雏,他們只是感情好楞件,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著裳瘪,像睡著了一般土浸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上彭羹,一...
    開(kāi)封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天黄伊,我揣著相機(jī)與錄音,去河邊找鬼派殷。 笑死还最,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的毡惜。 我是一名探鬼主播拓轻,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼经伙!你這毒婦竟也來(lái)了扶叉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎枣氧,沒(méi)想到半個(gè)月后溢十,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡达吞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年茶宵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宗挥。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖种蝶,靈堂內(nèi)的尸體忽然破棺而出契耿,到底是詐尸還是另有隱情,我是刑警寧澤螃征,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布搪桂,位于F島的核電站,受9級(jí)特大地震影響盯滚,放射性物質(zhì)發(fā)生泄漏踢械。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一魄藕、第九天 我趴在偏房一處隱蔽的房頂上張望内列。 院中可真熱鬧,春花似錦背率、人聲如沸话瞧。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)交排。三九已至,卻和暖如春饵筑,著一層夾襖步出監(jiān)牢的瞬間埃篓,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工根资, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留架专,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓嫂冻,卻偏偏與公主長(zhǎng)得像胶征,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子桨仿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

推薦閱讀更多精彩內(nèi)容

  • LINUX 基礎(chǔ)知識(shí) 1睛低、線程的概念 上下文切換 : 運(yùn)行程序前需要將相應(yīng)進(jìn)程信息讀入內(nèi)存,如果運(yùn)行進(jìn)程A后需要緊...
    Ycres閱讀 767評(píng)論 0 2
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)钱雷,斷路器骂铁,智...
    卡卡羅2017閱讀 134,672評(píng)論 18 139
  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司罩抗,掛了不少拉庵,但最終還是拿到小米、百度套蒂、阿里钞支、京東、新浪操刀、CVTE烁挟、樂(lè)視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,255評(píng)論 11 349
  • 老婆煮了點(diǎn)粥,問(wèn)我餓不餓骨坑。我搖了搖頭撼嗓,沒(méi)有一絲胃口,我打開(kāi)電視機(jī)想看看新聞欢唾,電視機(jī)里除了泡沫劇就是抗日劇且警,每個(gè)臺(tái)底...
    大黃蜂_a757閱讀 574評(píng)論 0 2
  • 本文重點(diǎn)針對(duì)android TV開(kāi)發(fā)的同學(xué),分析遙控或鍵盤按鍵事件后焦點(diǎn)的分發(fā)機(jī)制礁遣。尤其是剛從手機(jī)開(kāi)發(fā)轉(zhuǎn)向TV開(kāi)發(fā)...
    wanderingGuy閱讀 2,585評(píng)論 0 5