導航:首頁 > 編程語言 > vc2013mfc多線程編程

vc2013mfc多線程編程

發布時間:2022-08-14 19:58:21

1. 關於MFC中多線程問題

是哪個庫函數調用出錯?

訪問全局變數、讀寫文件,你做了線程之間同步互斥嗎?

可以用MsgWaitForMultipleObjects等待線程完成運算,而且不阻塞消息循環。

編譯鏈接通過應該跟編譯選項沒關系了。

但是有個問題:
的VC版本應該有3個參數才對呀,只有2個參數那是c#和VB的用法。

下面是VC的聲明:

HRESULT ([in] double screen_x,[in] double screen_y,[out, retval] IPointOnTerrainGE **pPoint)

2. MFC多線程編程的幾點經驗

1、不要在子線程操作UI控制項
2、如果你操作了,也絕對不能調用UpdateData來更新界面,否則程序Crash
3、這一條建立在第一條基礎上---你在子線程操作UI控制項,不可以讓主線程等待某些條件(如等待子線程關閉,而子線程正在操作UI、等待進

入臨界區,而子線程已經進入,並且操作UI),否則會出現假死...
4、最好方案:子線程操作數據,完成之後,通知主線程進行更新....

3. MFC的多線程問題:我做了個界面,上面有幾個按鈕,如查詢資料庫,顯示結果,等。

在VC++中利用MFC編程時,線程被分為工作者線程和用戶界面線程兩大類。前者用於處理後台任務,執行後台任務並不會耽擱用戶對應用程序的使用,即用戶操作無需等待後台任務的完成。後者常用來獨立的處理用戶輸入和響應用戶事件。
一個工作者線程的實現相當的簡單,只需要編寫線程式控制制函數和啟動函數就好。啟動函數:
CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
用戶界面線程的實現通常需要派生線程類、重載成員函數和啟動用戶界面線程。從MFC的CWindThread派生用戶界面線程類。父類CWinThread需要重載的函數主要有:InitInstance、ExitInstance和Run。其中InitInstance必須重載,而Run函數除非必要,一般無需重載。其中,啟動函數:
CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
建議學習Visual C++6.0編程使用技術與案例,看看多線程編程。。。。

4. VC/MFC 動態創建多線程

1. 因為你是MFC程序,建議使用AfxBeginThread()來創建新線程。AfxBeginThread()的內部會做一些相應的初始化,再調用CreateThread()API。 線程處理函數也就是一個普通的函數,但是其聲明形式有規定的,如下:
DWORD WINAPI ThreadProc (LPVOID pParam);
線程函數的名字由你自己定,但是格式必須是什麼這個聲明形式。比如:
DWORD WINAPI MyThreadFunction (LPVOID pParam)
{
// 函數體,這里你寫你的處理代碼。
// 只是在理解上,要注意的是,這個線程函數體裡面的代碼是
// 在新的線程中運行。雖然在源代碼上,這裡面的代碼和其他的代碼
// 存在於同一個文件中
}

「可是要在程序運行的才創建的線程,要怎麼處理呢」--》不明白你的這個子問題的意思。
新的線程都是在程序運行起來之後,由相應的創建函數創建的。沒有哪個線程是在編譯時創建的啊。

2. 同一個線程處理函數的代碼可以被多個線程共享的。可就是說,你可以只定義一個線程函數。不同的線程創建起來後,運行相同的代碼。可以通過傳遞不同的參數(這個參數可以在創建新線程時從外面傳遞進去),來讓線程函數體內的代碼有不同的運行邏輯。
DWORD WINAPI MyThreadFunction (LPVOID pParam /*線程的參數*/)
{
int nMyParam = (int)pParam;
if ( 0 == nMyParam ) { ... }
else if ( 1 == nMyParam ) { ...}
else if (...) {...}
}
對於線程函數的參數,它是LPVOID,但是你在外面可以給他傳遞一個整形,或者指針,然後在線程函數體內強制轉型回來使用。真正使用什麼數據類型,與你自己控制。

在理解上,也要注意理解多個線程運行同一份代碼的意思。
如果多個線程的線程函數讀寫同一個全局變數或者訪問同一個資源,就需要做同步控制。使用臨界區,Mutex等同步對象來控制。

對於多線程的運行機制的理解,比較重要。
理解了之後,你才能游刃有餘地控制它。要不然,很容易帶來問題。

5. 求mfc線程問題,

子線程中不能操作主線程的控制項具,體實現方法見上個提問,另外,UpdateData不要在子線程中用會卡的!

以下是我搜集的MFC多線程應注意的事項,很亂但很有用:

--------------------------------------------------------------------------------

MFC多線程編程注意事項 -
--------------------------------------------------------------------------------

關於啟動線程時傳輸窗口對象(指針?句柄?)的問題:

在選擇菜單中的開始線程後:
void cmainframe::onmenu_start()
{
...
afxbeginthread(mythread, this);
...
}

線程函數如下:
uint mythread(lpvoid pparam)
{
cmainframe* pmainfrm = (cmainframe *)pparam;
...
}

問題一:
這樣的代碼是不是有問題?
(文檔中說線程間不能直接傳輸mfc對象的指針,應該通過傳輸句柄實現)

問題二:
這樣使用開始好像沒有問題,直接通過pmainfrm訪問窗口中的view都正常。
但發現訪問狀態條時:
pmainfrm->m_wndstatusbar.setpanetext(2, "test);
出現debug assertion failed!(在窗口線程中沒有問題)
位置是wincore.cpp中的
assert((p = pmap->lookuppermanent(m_hwnd)) != null ||
(p = pmap->lookuptemporary(m_hwnd)) != null);
為什麼訪問view能正常,但訪問狀態條時不可以呢?

問題三:
如果通過傳輸句柄實現,怎樣做呢?
我用下面的代碼執行時有問題:
void cmainframe::onmenu_start()
{
...
hwnd hwnd = getsafehwnd();
afxbeginthread(mythread, hwnd);
...
}

uint mythread(lpvoid pparam)
{
cmainframe* pmainfrm = (cmainframe *)(cwnd::fromhandle((hwnd)pparam));
...
}
執行時通過線程中得到pmainfrm,訪問其成員時不正常。

網友:hewwatt
大致原因解釋如下:
1. mfc的大多數類不是線程安全的,cwnd及其消息路由是其中之最
2. mfc界面類的大多數方法,最後都是通過sendmessage實現的,而消息處理的
過程中會引發其他消息的發送及處理。如果消息處理函數本身不是線程安全的
你從工作線程中調用這些方法遲早會同你界面線程的用戶消息響應發生沖突
3. cxxxx::fromhandle會根據調用者所在線程查表,如果查不到用戶創建的cxxxx
對應對象,它會創建一個臨時對象出來。由於你在工作線程中調用該方法,當然不可能查到界面主線程中你所建立起來的那個對象了。這時mfc會你創建一個臨時對象並返回給你,你根本不可能期望它的成員變數會是有意義的。

所以要用也只能用cwnd::fromhandle,因為它只包含一個m_hwnd成員。 不過,要記住
跨線程直接或間接地調用::sendmessage,通常都是行為不可預測的。

1.工作線程給主線程發消息使用的是SendMessage和PoseMessage函數。這兩個函數的區別在於SendMessage函數是阻塞方式,而PoseMessage函數是非阻塞方式。如果不是嚴格要求工作線程與主線程必須同步執行,則推薦使用PoseMessage。

2.不要在線程函數體內操作MFC控制項,因為每個線程都有自己的線程模塊狀態映射表,在一個線程中操作另一個線程中創建的MFC對象,會帶來意想不到的問題。更不要在線程函數里,直接調用UpdataData()函數更新用戶界面,這會導致程序直接crash。而應該通過發送消息給主線程的方式,在主線程的消息響應函數里操作控制項。

3.在主線程中不要使用WaitForSingleObject和WaitForMultipleObjects兩個函數等待線程退出,其原因就是有導致程序死鎖的隱患,特別是線程函數里調用了SendMessage或是直接操作了MFC對象,更易出現此種現象。為解決這一問題,微軟特提供了一個函數,MsgWaitForMultipleObjects。

照著網上的例子,寫了在主線程中等待單個線程退出的程序:

DWORD dRet=-2;
MSG msg;
BOOL bWaitAll=FALSE;
int nWaitCount=2; //初始等待的線程數目
while (1)
{
dRet=MsgWaitForMultipleObjects(1,句柄的指 針,bWaitAll,INFINITE,QS_ALLINPUT);
if (dRet == WAIT_OBJECT_0 + 1)
{
TRACE("收到消息,函數返回值為%d \n",dRet);
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else if (dRet == WAIT_OBJECT_0 )
{
TRACE("線程退出了\n");
break;
}
}//end while
}

實際使用中,在主線程中使用WaitForMultipleObjects導致界面線程在子線程結束前失去響應,而使用MsgWaitForMultipleObjects則很好的解決了這個問題。

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/nefeithu123/archive/2009/06/07/4250002.aspx

1、盡量少的使用全局變數、static變數做共享數據,盡量使用參數傳遞對象。被參數傳遞的對象,應該只包括必需的成員變數。所謂必需的成員變數,就是必定會被多線程操作的。很多人圖省事,會把this指針(可能是任意一個對象指針)當作線程參數傳遞,致使線程內部有過多的操作許可權,對this中的參數任意妄為。整個程序由一個人完成,可能會非常注意,不會出錯,但只要一轉手,程序就會面目全非。當兩個線程同時操作一個成員變數的時候,程序就開始崩潰了,更糟的是,這種錯誤很難被重現。(我就在郁悶這個問題,我們是幾個人,把程序編成debug版,經過數天使用,才找到錯誤。而找到錯誤只是開始,因為你要證明這個bug被修改成功了,也非常困難。)其實,線程間數據交互大多是單向的,在線程回調函數入口處,盡可能的將傳入的數據備份到局部變數中(當然,用於線程間通訊的變數不能這么處理),以後只對局部變數做處理,可以很好的解決這種問題。
2、在MFC中請慎用線程。因為MFC的框架假定你的消息處理都是在主線程中完成的。首先窗口句柄是屬於線程的,如果擁有窗口句柄的線程退出了,如果另一個線程處理這個窗口句柄,系統就會出現問題。而MFC為了避免這種情況的發生,使你在子線程中調用消息(窗口)處理函數時,就會不停的出Assert錯誤,煩都煩死你。典型的例子就時CSocket,因為CSocket是使用了一個隱藏窗口實現了假阻塞,所以不可避免的使用了消息處理函數,如果你在子線程中使用CSocket,你就可能看到assert的彈出了。
3、不要在不同的線程中同時注冊COM組件。兩個線程,一個注冊1.ocx, 2.ocx, 3.ocx, 4.ocx; 而另一個則注冊5.ocx, 6.ocx, 7.ocx, 8.ocx,結果死鎖發生了,分別死在FreeLibrary和DllRegisterServer,因為這8個ocx是用MFC中做的,也可能是MFC的Bug,但DllRegisterServer卻死在GetMoleFileName里,而GetMoleFileName則是個API唉!如果有過客看到,恰巧又知道其原因,請不吝賜教。
4、不要把線程搞的那麼復雜。很多初學者,恨不能用上線程相關的所有的函數,這里互斥,那裡等待,一會兒起線程,一會兒關線程的,比起goto語句有過之而無不及。好的多線程程序,應該是盡量少的使用線程。這句話怎麼理解吶,就是說盡量統一一塊數據共享區存放數據隊列,工作子線程從隊列中取數據,處理,再放回數據,這樣才會模塊化,對象化;而不是每個數據都起一個工作子線程處理,處理完了就關閉,寫的時候雖然直接,等維護起來就累了。

6. VC中MFC創建了多線程,界面怎麼還會有卡死現象,但程序在正確執行(可以執行出結果)

創建完線程後主線程 Sleep(time*1000+100);
當然卡死了

7. 怎麼在基於對話框的MFC程序中實現多線程

基於MFC的對話框程序加啟動進度條(轉)
對於比較大的程序,在啟動的時候都會顯示一個畫面,以告訴用戶程序正在載入,或者顯示一些關於軟體的信息,如Visual C++,Word, PhotoShop等。
這些啟動畫面在Visual C++中怎麼實現呢?對於文檔/視圖結構的程序,可以直接使用VC提供的SplashWnd組件。可是在基於對話框的程序卻不能使用SplashWnd組件。因此只能自己來實現此功能。
因為顯示啟動畫面的同時還要進行程序的載入工作,所以要用到多線程。MFC區分了兩種不同類型的多線程:用戶界面(UI)線程和工作者線程。兩者的區別是UI線程有消息循環,而工作者線程沒有,UI線程能夠創建窗口並處理發送給窗口的消息。工作者線程用來執行後台任務,這些後台任務不直接接受用戶輸入,因此不需要窗口和消息循環。 因為這里要顯示一個畫面,所以要使用UI線程。

下面結合我做的一個小軟體「實用鬧鍾」來說明如何為對話框程序製作啟動畫面。
打開Visual C++建立一個對話框工程Page.
首先准備一副點陣圖資源插入到工程中,作為啟動時顯示的畫面。再插入一個對話框,設置ID為IDD_SPLASH。在上面放一個picture控制項,類型設為」Bitmap」,圖象選擇剛才插入的點陣圖。
設置對話框的Style為Popup,Border 為None,去掉Title Bar屬性,並調整對話框的大小與點陣圖等大,這樣對話框顯示的時候,你看到的只是圖片。打開 ClassWizard為此對話框建立一個新類CSplashDlg, 基類為CDialog.
UI線程是由一個動態可創建的類來控制,該類是從CWinThread派生的,非常類似從CWinApp派生的一個應用程序類.打開ClassWizard建立一個由CWinThread派生的類----CSplashThread,在SplashThread.h 中加入 #include"SplashDlg.h",並添加一個protected型指針變數:
CSplashDlg* m_pSplashDlg; //聲明一個對話框指針

下面我們將在UI線程的InitInstance()函數中調用剛才創建的對話框並顯示。
BOOL CSplashThread::InitInstance()
{
::AttachThreadInput(m_nThreadID, AfxGetApp()->m_nThreadID, TRUE );
//:通常系統內的每個線程都有自己的輸入隊列。本函數允許線程和進程共享輸入隊列。連接了線程後,輸入焦點、窗口激活、滑鼠捕獲、鍵盤狀態以及輸入隊列狀態都會進入共享狀態 . (這個函數可以不用)
m_pSplashDlg=new CSplashDlg;
m_pSplashDlg->SetEnable(true);
m_pSplashDlg->Create(IDD_SPLASH);
m_pSplashDlg->ShowWindow(SW_SHOW);
return true;
}

為CSplashThread類添加一個函數HideSplash(), 用來隱藏啟動畫面(即關閉對話框)
void CSplashThread::HideSplash()
{
m_pSplashDlg->SendMessage(WM_CLOSE);
}

在ExitInstance()中釋放資源:
int CSplashThread::ExitInstance()
{
m_pSplashDlg->DestroyWindow();
delete m_pSplashDlg;
return CWinThread::ExitInstance();
}

在應用程序類CPageApp中包含頭文件: #include 「SplashThread.h」
並添加兩個變數:
public: //設為pulic類型,是為了在其他類中能夠訪問
CSplashThread* pSplashThread;
CSplashDlg* m_pSplashDlg;

在InitInstance()中啟動UI線程:
pSplashThread = (CSplashThread*) AfxBeginThread(
RUNTIME_CLASS(CSplashThread),
THREAD_PRIORITY_NORMAL,
0, CREATE_SUSPENDED);
ASSERT(pSplashThread->IsKindOf(RUNTIME_CLASS(CSplashThread)));
pSplashThread->ResumeThread();
Sleep(1);

為了讓程序一起動就顯示啟動畫面,這段代碼應該放在InitInstance()最開頭的地方.
啟動畫面是顯示了,可是結束代碼應該放在什麼地方呢?如果放在InitInstance()的CPageDlg dlg; m_pMainWnd = &dlg; 後面,即在構造了主對話框之後隱藏啟動畫面, 程序運行時會發現,啟動畫面結束後,還要等一會才能顯示出主對話框,這樣就達不到啟動畫面應有的效果. 最好應該在即將顯示主對話框的時候隱藏啟動畫面. 我的這個軟體中在主對話框中定義了5個子對話框類的對象,分別是page1,page2,…page5.
程序啟動時的流程如下:
Page1構造 --->Page2構造 --->Page3構造---> Page4構造---> Page5構造---> 主對話框構造 --->主對話框初始化---> Page1初始化---> Page2初始化 --->Page3初始化 Page4初始化---> Page5初始化
由此可見,啟動畫面結束的最好地方應該是在 page5的初始化函數中
BOOL CPage5::OnInitDialog()
{
CDialog::OnInitDialog();
if ( ((CPageApp*)AfxGetApp())->pSplashThread != NULL)
((CPageApp*)AfxGetApp())->pSplashThread->HideSplash();
return TRUE;
}
到此,一個對話框程序的啟動畫面就這樣完成了.由於是用對話框作為啟動畫面,所以你可以你可以發揮你的想像力,在對話框上設計出豐富多才的效果來,比如加上Flash,Gif動畫等.

8. mfc創建線程的三種方法

MFC中有兩類線程,分別稱之為工作者線程和用戶界面線程。二者的主要區別在於工作者線程沒有消息循環,而用戶界面線程有自己的消息隊列和消息循環。
工作者線程沒有消息機制,通常用來執行後台計算和維護任務,如冗長的計算過程,列印機的後台列印等。用戶界面線程一般用於處理獨立於其他線程執行之外的用戶輸入,響應用戶及系統所產生的事件和消息等。但對於Win32的API編程而言,這兩種線程是沒有區別的,它們都只需線程的啟動地址即可啟動線程來執行任務

1、WIN的API函數CreateThread

HANDLE CreateThread(
LPSECURITY_ATTRIBUTESlpThreadAttributes, // SD
DWORDdwStackSize, // initial stack size
LPTHREAD_START_ROUTINElpStartAddress, // thread function
LPVOIDlpParameter, // thread argument
DWORDdwCreationFlags, // creation option
LPDWORDlpThreadId // thread identifier
);
//lpThreadAttributes:指向SECURITY_ATTRIBUTES型態的結構的指針。在Windows 98中忽略該參數。在Windows NT中,它被設為NULL,表示使用預設值。

dwStackSize,線程堆棧大小,一般=0,在任何情況下,Windows根據需要動態延長堆棧的大小。

lpStartAddress,指向線程函數的指針,形式:@函數名,函數名稱沒有限制,但是必須以下列形式聲明:

DWORD WINAPI ThreadProc (LPVOID lpParam) ,格式不正確將無法調用成功。

lpParameter:向線程函數傳遞的參數,是一個指向結構的指針,不需傳遞參數時,為NULL。

dwCreationFlags :線程標志,可取值如下

(1)CREATE_SUSPENDED-----創建一個掛起的線程,

(2)0---------------------------------表示創建後立即激活。

lpThreadId:保存新線程的id。

2、MFC的全局函數AfxBeginThread

CWinThread* AfxBeginThread( AFX_THREADPROCpfnThreadProc, LPVOIDpParam, intnPriority= THREAD_PRIORITY_NORMAL, UINTnStackSize= 0, DWORDdwCreateFlags= 0, LPSECURITY_ATTRIBUTESlpSecurityAttrs= NULL );

//用於創建工作者線程 其中pfnThreadProc指向線程函數 pParam為傳遞給線程函數的參數

CWinThread* AfxBeginThread( CRuntimeClass*pThreadClass, intnPriority= THREAD_PRIORITY_NORMAL, UINTnStackSize= 0, DWORDdwCreateFlags= 0, LPSECURITY_ATTRIBUTESlpSecurityAttrs= NULL );

//用於創建用戶界面線程 其中pThreadClass為CWinThread派生對象的RUNTIME_CLASS

3、MFC的CWinThread類的CreateThreat成員函數

BOOL CreateThread( DWORD dwCreateFlags = 0, UINT nStackSize = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );

//CWinThread類支持工作者線程和用戶界面線程 可以將一個CWinThread派生類的CRUNTIMECLASS的指針作為參數傳遞給AfxBeginThread函數以創建一個用戶界面線程 CWinThread類的CreateThread成員函數創建一個調用進程的地址空間中執行的線程

VC 6.0 創建線程的三種方法

CreateThread/ExitThread
_beginthreadex/_endthreadex
AfxBeginThread /AfxEndThread

對以上三種方式的選擇:

1.在使用了MFC的程序中使用AfxBeginThread函數或者CWinThread::CreateThread函數創建線程。

2.在非MFC工程中,如果要創建多線程,建議使用_beginthreadex

3.避免使用CreateThread函數。不使用_beginthread.

4.線程內部退出函數使用與創建函數配套的函數。

9. VC++中如何用多線程

你說的是MFC嗎?MFC可以用AfxBeginThread函數創建線程,可以把ThreadProc聲明為類的靜態成員函數,你會單線程下載頁面,要在多線程下下載頁面就不成問題了哈.
推薦你看看<WIN32多線程程序設計>
www.infoxa.com上有下載

10. MFC中實現多線程

MFC CThread 去看下就會啦。。等待就是一個WaitForSingleObject函數

閱讀全文

與vc2013mfc多線程編程相關的資料

熱點內容
做賬為什麼要用加密狗 瀏覽:583
考研群體怎麼解壓 瀏覽:156
linux修改命令提示符 瀏覽:224
圓圈裡面k圖標是什麼app 瀏覽:59
pdf加空白頁 瀏覽:945
linux伺服器如何看網卡狀態 瀏覽:316
解壓新奇特視頻 瀏覽:704
圖書信息管理系統java 瀏覽:552
各種直線命令詳解 瀏覽:862
程序員淚奔 瀏覽:147
素材怎麼上傳到伺服器 瀏覽:516
android百度離線地圖開發 瀏覽:189
web可視化編程軟體 瀏覽:293
java筆試編程題 瀏覽:746
win11什麼時候可以裝安卓 瀏覽:564
java不寫this 瀏覽:1001
雲點播電影網php源碼 瀏覽:97
pythonclass使用方法 瀏覽:226
移動加密軟體去哪下載 瀏覽:294
php彈出alert 瀏覽:209