上一篇籠統介紹瞭如何創建線程以及線程如何和類成員函數通信,本篇將主要介紹:
線程的相關操作
1.線程的掛起和恢復:SuspendThread、ResumeThread
在線程創建並運行後,用戶可以對線程執行掛起和恢復操作
掛起就是指暫停線程的執行,有暫停就有恢復,之後用戶可以通過指定的操作來恢復線程的正常執行。
注意:線程的掛起和恢復是有次數限制的,可以進行多次掛起,但之後想要正常執行就需要多次恢復操作。
//線程函數
UINT __cdecl CThreadDlg::MyControllingFunction(LPVOID pParam)
{
int tipMes = (int)pParam;
CString strMsg;
while (TRUE)
{
strMsg.Format(_T("%d"), tipMes++);
OutputDebugString(strMsg);
Sleep(100);
}
return 100;
}
//定義一個線程句柄
HANDLE hThread = NULL;
//開啓一個線程
void CThreadDlg::OnBnClickedCreatethraedButton()
{
// TODO: 在此添加控件通知處理程序代碼
CWinThread* pThread = AfxBeginThread(MyControllingFunction, (LPVOID)123);
hThread = pThread->m_hThread;//獲得線程的句柄
}
void CThreadDlg::OnBnClickedSuspendthreadButton2()
{
// TODO: 在此添加控件通知處理程序代碼
SuspendThread(hThread);
}
void CThreadDlg::OnBnClickedResumethreadButton3()
{
// TODO: 在此添加控件通知處理程序代碼
ResumeThread(hThread);
}
2.線程的相對優先級
線程的相對優先級總共有七個優先級,分別爲:
- THREAD_PRIORITY_TIME_CRITICAL 關鍵時間(最高)
- THREAD_PRIORITY_HIGHEST 最高,其實是次高
- THREAD_PRIORITY_ABOVE_NORMAL 高於標準
- THREAD_PRIORITY_NORMAL 標準
- THREAD_PRIORITY_BELOW_NORMAL 低於標準
- THREAD_PRIORITY_LOWEST 最低,其實是次底
- THREAD_PRIORITY_IDLE 空閒,最低
在AfxBeginThread創建的線程時候指定,而CreateThread可以在創建後在指定,可以通過下面兩個函數進行設置:
獲取:GetThreadPriority
設置:SetThreadPriority
設置線程優先級的目的:
1.cpu會以更多的的時間執行高優先級的線程
2.高優先級的線程可以打斷低優先級的線程
3.線程的退出與終結
1.最好的方式:讓線程函數主動退出,或者return;
可以保證線程函數裏面的對象的析構函數被調用,以及線程申請的相關空間被釋放;
2.線程自己主動退出,win32API可以調用ExitThread(MFC中使用AfxEndThread);
線程函數裏面的對象的析構函數不會被調用,線程申請的相關空間被釋放,所以,在c語言裏可以使用該函數退出線程,但是c++不建議這樣使用,因爲c++有類,需要調用析構函數才能釋放類的資源
3.其他程序的強行結束線程:
可以調用TerminateThread,此函數非常危險,
被結束的線程不會得到任何通知,線程申請的相關資源也不會被釋放,所以謹慎使用。
4.線程退出碼的獲取:
GetExitCodeThread,前提是句柄有效,不被關閉。
在使用退出碼時
HANDLE hThread = NULL;
DWORD dwExitCode = 0;
//開啓線程,同時關閉自動釋放線程,同時把句柄導出以此獲取線程函數結束返回碼
CWinThread* pThread = AfxBeginThread(StartCameraTest, NULL, THREAD_PRIORITY_NORMAL, 0, 0, NULL);
pThread->m_bAutoDelete = FALSE;//關閉自動釋放資源的設置
hThread = pThread->m_hThread;//獲取句柄
//獲取線程函數的返回碼
GetExitCodeThread(hThread, &dwExitCode);
//如果線程結束,返回碼dwExitCode爲100該值在線程函數最後return即可,值可以自己設定,但是有個限制,具體請查看文檔,此時在釋放線程句柄就安全了,同時把返回碼初始成0
CloseHandle(hThread);
dwExitCode = 0;
線程間的通信
1.全局變量方式:
定義一個全局變量,開啓兩個線程,一個對變量進行自增操作,一個進行讀取
//全局變量
int g_Num = 100;
//寫數據線程
UINT __cdecl CThreadDlg::ThreadWriteProc(LPVOID pParam)
{
while (TRUE)
{
++g_Num;
Sleep(50);
}
return 100;
}
//讀數據線程
UINT __cdecl CThreadDlg::ThreadReadProc(LPVOID pParam)
{
CString strMsg;
while (TRUE)
{
strMsg.Format(_T("%d"), g_Num);
OutputDebugString(strMsg);
Sleep(50);
}
}
//定義一個線程句柄
HANDLE hThread = NULL;
//開啓一個線程
void CThreadDlg::OnBnClickedCreatethraedButton()
{
// TODO: 在此添加控件通知處理程序代碼
CWinThread* pThread = AfxBeginThread(ThreadWriteProc, NULL);
hThread = pThread->m_hThread;//獲得線程的句柄
AfxBeginThread(ThreadReadProc, NULL);
}
這個是在同一個.cpp文件夾開啓的兩個線程和定義的兩個全局變量,如果開啓的線程在不同的.cpp文件下,如何申請全局變量呢?其實簡單加入在1.cpp定義全局變量int a=100;在2.cpp中如何引用這個全局變量的a呢?只需在1.cpp的頭文件1.h里加入extern int a;然後其它文件包含該頭文件即可。
1.h
Extern int a;
1.cpp
Int a = 100;
2.h
#include "1.h"
2.cpp
直接可以使用全局變量a
2.多個線程都能看到的東西即類的成員
在類中聲明如下:
public:
CThreadDlg(CWnd* pParent = nullptr); // 標準構造函數
static UINT __cdecl MyControllingFunction(LPVOID pParam);
static UINT __cdecl ThreadWriteProc(LPVOID pParam);
static UINT __cdecl ThreadReadProc(LPVOID pParam);
int m_Num;
//寫數據線程
int g_Num = 100;
UINT __cdecl CThreadDlg::ThreadWriteProc(LPVOID pParam)
{
CThreadDlg* pThis = (CThreadDlg*)pParam;
while (TRUE)
{
++(pThis->m_Num);
Sleep(50);
}
return 100;
}
//讀數據線程
UINT __cdecl CThreadDlg::ThreadReadProc(LPVOID pParam)
{
CThreadDlg* pThis = (CThreadDlg*)pParam;
CString strMsg;
while (TRUE)
{
strMsg.Format(_T("%d"), (pThis->m_Num));
OutputDebugString(strMsg);
Sleep(50);
}
}
//定義一個線程句柄
HANDLE hThread = NULL;
//開啓一個線程
void CThreadDlg::OnBnClickedCreatethraedButton()
{
// 初始化類中的變量m_Num
m_Num = 0;
//開啓的線程是無法直接處理類中的變量的,需要傳入類的地址。同時我們知道
//該類的就是主對話框,因此直接把主對話框的地址;傳給他即可,如:
CWinThread* pThread = AfxBeginThread(ThreadWriteProc, this);
hThread = pThread->m_hThread;//獲得線程的句柄
AfxBeginThread(ThreadReadProc, this);
}
3.發消息的方式:PostThreadMessage
該方式需要自定義消息,和綁定,然後一個線程進行消息的發送,另一個線程不停的等待消息和篩選消息類型即只接收我們自定義的消息,一旦接收到立馬執行,整體流程是這樣的,因爲還沒深入學習MFC編程,所以這裏先放放,以後用到了在系統的總結,但是總體思路是這樣的
4.與界面線程相聯繫
1.創建界面線程的返回值CWinThread類型指針,就是新線程的指針,也因此可以通過強制類型轉換對先創建的界面線程進行賦值和信息傳遞,這裏大家需要調試一下。因爲界面線程的是沒有參數傳遞,那怎麼才能把值傳遞給新的線程呢?就是通過強制類型的轉換:
class CUIThreadApp :
public CWinThread
{
public:
int num;
};
CWinThread* pThread = AfxBeginThread(RUNTIME_CLASS(CUIThreadApp), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
((CUIThreadApp*)pThread)->num = 456;
在初始程序中就好創建這個類的對象,然後類成員的變量num就爲456.
這裏是通過主線程向子線程進行傳遞信息,如何在子線程中獲取主線程的信息呢
2.在新界面線程中調用AfxGetApp();獲取到的是主線程的指針,通過強制類型轉換就可以獲取主線程的信息了。
3、通過PostThreadMessage方式進行通信,界面線程同樣適用,重載界面線程類的PreTranslateMessage即可
以上就是線程間的通信