摘要:本文主要以mfc線程為主題展開(kāi)的概述,詳細(xì)介紹了線程,線程與函數(shù)以及實(shí)例來(lái)說(shuō)明,下面我們一起來(lái)看看原文。
線程簡(jiǎn)介
我們知道一般情況程序中的代碼都是按順序從頭開(kāi)始一行一行的執(zhí)行以最后。中間不能出現(xiàn)同時(shí)執(zhí)行的情況。比如一段代碼調(diào)用兩個(gè)函數(shù)
FunOne();
FunTwo();
只要當(dāng)函數(shù)FunOne中的代碼執(zhí)行完才返回來(lái)執(zhí)行FunTwo.假如邏輯上是有先后順序那還真只能這樣按順序執(zhí)行下來(lái)。不過(guò)有假如FunOne與FunTwo沒(méi)有邏輯先后順序,是相互獨(dú)立的。比如兩個(gè)函數(shù)分別處理兩不同的文件one.text與two.txt.
這種情形就可以用到線程,弄兩個(gè)線程去執(zhí)行這兩函數(shù)。這樣兩函數(shù)同時(shí)執(zhí)行,提高了效率(如果單核的CPU可能沒(méi)有真正的并行效果不明顯,那多核CPU執(zhí)行多線程那是能夠真正達(dá)到并行執(zhí)行,效果很明顯的)。
實(shí)際上可以這樣簡(jiǎn)單的理解線程,它是CPU的調(diào)度單位。而一個(gè)線程是對(duì)應(yīng)一個(gè)函數(shù)。所以別把一個(gè)線程想得太復(fù)雜,就只是執(zhí)行個(gè)函數(shù)而已。只不過(guò)執(zhí)行的時(shí)候是并行執(zhí)行罷了。如果只是簡(jiǎn)單的幾個(gè)線程不涉及使用共同的資源,沒(méi)其他啥關(guān)聯(lián)。就完全跟簡(jiǎn)單的執(zhí)行一個(gè)函數(shù)類似。只是如果多個(gè)線程間關(guān)系復(fù)雜就會(huì)涉及到啥同步問(wèn)題,那樣就有很多復(fù)雜的細(xì)節(jié)性問(wèn)題。
線程間通信的方式
方式一:全局變量,各線程通過(guò)修改全局變量傳遞信息,通過(guò)循環(huán)檢測(cè)查看信息。 方式二:消息傳遞,通過(guò)windows消息機(jī)制傳遞。
方式一問(wèn)題主要有兩個(gè):第一是全局變量過(guò)多,不便于管理;第二個(gè)是循環(huán)檢測(cè)過(guò)于緩慢,并且較不靈活,不能夠迅速響應(yīng)變化。
MFC中存在三種線程
A、 Ui線程:通過(guò)創(chuàng)建窗口得到,具備標(biāo)準(zhǔn)窗口的功能。
B、 工作者線程:通過(guò)CreateThread函數(shù)直接創(chuàng)建,不具備消息隊(duì)列。
C、 帶消息隊(duì)列的工作者線程:通過(guò)繼承CWinThread得到,具備消息隊(duì)列。
A種和C種線程使用消息隊(duì)列,對(duì)于使用者來(lái)說(shuō),這兩種線程需要自己本身或其他線程向其發(fā)送消息,才進(jìn)行相應(yīng)工作,否則保持靜默狀態(tài),該兩種線程擅長(zhǎng)實(shí)時(shí)處理外部信號(hào)。 B種線程不使用消息隊(duì)列,可以用單個(gè)函數(shù)作為其線程的本體,適合處理步驟相對(duì)固定的算法。
線程與函數(shù)
線程函數(shù)必須是全局函數(shù),或者是類的靜態(tài)成員函數(shù),因?yàn)榉庆o態(tài)成員函數(shù)有this指針,而在進(jìn)程中無(wú)法訪問(wèn)此指針。
但是靜態(tài)成員函數(shù)只能訪問(wèn)靜態(tài)成員,解決此問(wèn)題途徑:
1. 就是在調(diào)用靜態(tài)成員函數(shù)時(shí)將this指針作為參數(shù)傳入,通過(guò)該指針訪問(wèn)非靜態(tài)成員。
2. 不將線程函數(shù)定義為類的靜態(tài)成員函數(shù),而是定義為類的友元函數(shù),這樣函數(shù)線程也可以有類成員函數(shù)相同的權(quán)限。
最簡(jiǎn)單示例
線程分工作線程與界面線程。這里就以工作線程為例
1.先來(lái)看個(gè)MFC中的創(chuàng)建線程的簡(jiǎn)單例子。
UINT ThreadFun(LPVOID pParam){ //線程要調(diào)用的函數(shù)
MessageBox(NULL,_T(“i am called by a thread.”), _T(“thread func”),MB_OK);
}
?。海篈fxBeginThread(ThreadFun, NULL); //這就是創(chuàng)建一個(gè)線程并執(zhí)行了,調(diào)用上面的函數(shù)彈出一個(gè)對(duì)話框。
2.示例分析
上面的線程是簡(jiǎn)單的不能再簡(jiǎn)單了吧。下面從兩個(gè)來(lái)分析下。
a.首先是被調(diào)用的函數(shù)有啥講究不? 當(dāng)然有,被線程用到的函數(shù)格式必須是統(tǒng)一的,返回類型必須是UINT,函數(shù)只能有一個(gè)參數(shù)LPVOID.其中UINT就是個(gè)無(wú)符號(hào)的整形,LPVOID是void*,所以這個(gè)參數(shù)表示可以傳任何類型的指針過(guò)來(lái)的。
b.函數(shù)AfxBeginThread的分析。
這個(gè)函數(shù)還有返回值CWinThread*的,如果你只是簡(jiǎn)單的創(chuàng)建一個(gè)線程并執(zhí)行,就不用管了。但如果想要對(duì)創(chuàng)建的線程做其他操作就必須這樣寫。
CWinThread* pThread = ::AfxBeginThread(ThreadFun, NULL); //接下來(lái)做啥就直接調(diào)用pThead就行。
另外函數(shù)AfxBeginThread的參數(shù)有很多個(gè),但很多都有默認(rèn)值。下面是完整的參數(shù)
CWinThread* AfxBeginThread(
AFX_THREADPROC pfnThreadProc, //一個(gè)函數(shù)指針
LPVOID pParam, //void*類型的指針,可以傳任何種類指針過(guò)來(lái)。
int nPriority = THREAD_PRIORITY_NORMAL, //線程優(yōu)先級(jí)
UNT nStackSize = 0, //分配堆棧大小
DWORD dwCreateFlags = 0, //表示線程創(chuàng)建后是立即執(zhí)行還是等會(huì)執(zhí)行
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL //線程安全屬性指針
?。?//用于創(chuàng)建工作者線程
上面的參數(shù)我們用的最多的是3個(gè),其他一盤都默認(rèn)值。
AFX_THREADPROC pfnThreadProc //函數(shù)指針肯定是必須要指定的,不然線程執(zhí)行哪個(gè)函數(shù)去啊
LPVOID pParam //這是傳給上面指定函數(shù)的參數(shù)。如果被調(diào)用的函數(shù)需要啥參數(shù)就只能在這里指定了。
DWORD dwCreateFlags //默認(rèn)值為0表示創(chuàng)建線程后立即執(zhí)行。如果是CREATE_SUSPEND則表示創(chuàng)建好后先掛起。必須通過(guò)ResumeThread來(lái)執(zhí)行。
稍復(fù)雜的例子
擴(kuò)充下上面的例子,給函數(shù)傳入?yún)?shù),并且休眠和掛起線程。
UINT ThreadFun(LPVOID pParam){ //線程要調(diào)用的函數(shù)
int* pNum = (int*)pParam; //假如會(huì)傳入一個(gè)整形指針參數(shù)
MessageBox(NULL,_T(“i am called by a thread.”), _T(“thread func”),MB_OK);
}
CWinThread* pThread; //定義一個(gè)線程指針
void CreateThread(){//創(chuàng)建一個(gè)線程并掛起
int* pNum = new int(88); //傳入的參數(shù)
pThread = ::AfxBeginThread(ThreadFun, pNum,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
}
void StartThread(){ //運(yùn)行線程
pThread-》ResumeThread();
}
線程休眠與掛起的區(qū)別
上面示例中先創(chuàng)建一個(gè)線程,并讓它掛起。(suspend),被掛起的線程只有通過(guò)ResumeThread才能開(kāi)始執(zhí)行。
而休眠則一般是這樣使用。
UINT ThreadFun(LPVOID pParam){ //線程要調(diào)用的函數(shù)
?。海篠leep(1000); //表示函數(shù)執(zhí)行到這里先休息1000微秒,也就是1秒。然后再接著執(zhí)行下面的語(yǔ)句。
MessageBox(NULL,_T(“i am called by a thread.”), _T(“thread func”),MB_OK);
}
所以休眠一般是會(huì)在線程調(diào)用的那個(gè)函數(shù)中指定。休眠在指定的時(shí)間后會(huì)自動(dòng)再次執(zhí)行,相當(dāng)于暫停一斷時(shí)間然后又自動(dòng)活過(guò)來(lái)了,不用像掛起還必須得顯式去啟動(dòng)才行。
內(nèi)核對(duì)象與進(jìn)程
內(nèi)核對(duì)象
這里的對(duì)象不不是指一個(gè)類的實(shí)例化,不過(guò)實(shí)際上也可以類似的等同。因?yàn)閮?nèi)核對(duì)象是內(nèi)核分配的一個(gè)內(nèi)存塊,這種內(nèi)存塊就是一個(gè)結(jié)構(gòu)體(struct)。應(yīng)用程序若需要訪問(wèn)內(nèi)核對(duì)象需要通過(guò)一些API函數(shù),不能直接訪問(wèn)(基于安全的考慮)。內(nèi)核對(duì)象的擁有者是內(nèi)核,所以何時(shí)釋放對(duì)象的內(nèi)存是由內(nèi)核決定的。我們使用內(nèi)核對(duì)象時(shí)一般是通過(guò)一個(gè)句柄支間接的使用,于是每有一個(gè)句柄與對(duì)象關(guān)聯(lián)則對(duì)象的引用計(jì)數(shù)加1,當(dāng)系統(tǒng)發(fā)現(xiàn)內(nèi)核對(duì)象的引用計(jì)數(shù)為0時(shí)則釋放內(nèi)核對(duì)象內(nèi)存。(看起來(lái)是不是有點(diǎn)像智能指針的用法了???)
進(jìn)程與內(nèi)核對(duì)象
每個(gè)進(jìn)程在初始化時(shí)被分配一個(gè)句柄表,表中保存進(jìn)程能訪問(wèn)的所有內(nèi)核對(duì)象的句柄(進(jìn)程是不能直接訪問(wèn)內(nèi)核對(duì)象,只能先在找到句柄表中的句柄,然后再使用內(nèi)核對(duì)象。)
當(dāng)然進(jìn)程還能通過(guò)CreateObject來(lái)創(chuàng)建一些內(nèi)核對(duì)象,然后不使用時(shí)使用CloseHandle來(lái)關(guān)閉內(nèi)核對(duì)象。
如果某個(gè)進(jìn)程創(chuàng)建內(nèi)核對(duì)象時(shí)指定SECURITY_ATTRIBUTES中的bInheritHandle為TRUE,創(chuàng)建子進(jìn)程時(shí)(CreateProcess也設(shè)bInheritHandle為TRUE)則子進(jìn)程也能擁有那個(gè)內(nèi)核對(duì)象的訪問(wèn)權(quán)限(此時(shí)子進(jìn)程的句柄表會(huì)復(fù)制該內(nèi)核對(duì)象句柄過(guò)來(lái),內(nèi)核對(duì)象引用計(jì)數(shù)加1)。當(dāng)然如果父進(jìn)程在創(chuàng)建了子進(jìn)程之后再生成一些內(nèi)核對(duì)象,則子進(jìn)程是不會(huì)繼承那訪問(wèn)權(quán)限的。
除了通過(guò)繼承可以獲得某個(gè)內(nèi)核對(duì)象的訪問(wèn)權(quán)限外還可以通過(guò)同名共享(不過(guò)需要內(nèi)核對(duì)象支持這種共享方式,不是所有種類的內(nèi)核對(duì)象支持)。當(dāng)然通過(guò)CreateObject來(lái)創(chuàng)建好一個(gè)名為test1的內(nèi)核對(duì)象后,此時(shí)如果有另外的進(jìn)程再創(chuàng)建一個(gè)名為test1的內(nèi)核對(duì)象那不會(huì)真的創(chuàng)建,而只是返回之前已創(chuàng)建好的test的句柄(看起來(lái)有點(diǎn)像是單例模式的應(yīng)用啊)
另外還可以通過(guò)復(fù)制內(nèi)核對(duì)象的句柄,通過(guò)DuplicateHandle,當(dāng)然了前提是進(jìn)程要有對(duì)那個(gè)句柄的訪問(wèn)權(quán)限先。(在句柄表中有)
線程與進(jìn)程
進(jìn)程只是個(gè)容器,不會(huì)執(zhí)行任何操作。它里面有很多線程(至少必須有一個(gè)主線程)。進(jìn)程內(nèi)的所有線程共享進(jìn)程的內(nèi)核對(duì)象。
當(dāng)一個(gè)進(jìn)程中止時(shí)所以線程自然中止。
評(píng)論
查看更多