程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 多線程編程的一點小心得(1)

多線程編程的一點小心得(1)

編輯:關於C語言

最近有了很多想法,想把我用過的東西都吃透,這樣才不會變成所謂的“樣樣通樣樣松”。我是新手,老鳥請飄過,當然,這篇小心得如果有什麼毛病,還請指出來。先行謝過!

其實我本來想把博客當作自己的日記,記錄下學習的點點滴滴,寫下的就代表是學會的東西,人家說好記性不如爛筆頭嘛。

一直以來對多線程這塊就迷迷糊糊的,用得不太多,即便是用了,也是把以前寫的代碼拿出來,稍微修改一下,就適應了新的需求。也看過一些資料,但都沒實踐過,所以就馬馬虎虎地,能夠適應工作需求就得過且過。其實這種思想是非常錯誤的。做技術一定要踏實,否則就無法成長。

閒話少說書歸正傳,接下來的幾篇就把多線程的東西學習、總結一下。先上一段萬金油:
線程:有時被稱為輕量級進程(Lightweight Process,LWP),是程序執行流的最小單元。一個標准的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成。另外,線程是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程自己不擁有系統資源,只擁有一點在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的全部資源。一個線程可以創建和撤消另一個線程,同一進程中的多個線程之間可以並發執行。由於線程之間的相互制約,致使線程在運行中呈現出間斷性。線程也有就緒、阻塞和運行三種基本狀態。每一個程序都至少有一個線程,那就是程序本身。

自從有了線程,這個世界就變得吵起來了,線程的周期、調度與優先級、資源共享、線程同步、守護線程、死鎖、信號量。。後面咱們再慢慢研究這些東西吧,今天先來簡單明白線程到底是什麼,怎麼應用在編程中。

老慣例,上個程序吧。建立一個標准的基於對話框的MFC程序,拖一個edit控件和一個button在上面,資源命名分別為ID_EDIT_NUMBER和ID_BUTTON_START。給edit控件關聯一個變量CEdit * m_editNumber。弄差不多這個樣子就行。

 先寫一個線程函數,告訴電腦在這個線程裡要做什麼。

  1. DWORD _stdcall ThreadProc(LPVOID lpParameter) 
  2.     CMultithreadTestDlg * dlg = (CMultithreadTestDlg*) lpParameter; 
  3.     CString szCounter; 
  4.  
  5.     for(int i = 0; i < 10000; i++) 
  6.     { 
  7.         szCounter.Format(_T("%d"), i); 
  8.         dlg->m_editNumber.SetWindowTextW(szCounter); 
  9.         szCounter.ReleaseBuffer(); 
  10.     } 
  11.  
  12.     return 0; 

很簡單,就是讓edit控件顯示不停增加的數字。 

接下來就要想辦法啟動這個線程。

在CMultithreadTestDlg中添加一個成員變量HANDLE m_hThread。雙擊start按鈕,編寫按鈕的單擊事件。

  1. void CMultithreadTestDlg::OnBnClickedButtonStart() 
  2.     // TODO: Add your control notification handler code here 
  3.     m_hThread = CreateThread(NULL, 0, ThreadProc, this, 0, NULL); 

CreateThread函數的原型如下:

  1. HANDLE WINAPI CreateThread( 
  2.   __in_opt   LPSECURITY_ATTRIBUTES lpThreadAttributes, 
  3.   __in       SIZE_T dwStackSize, 
  4.   __in       LPTHREAD_START_ROUTINE lpStartAddress, 
  5.   __in_opt   LPVOID lpParameter, 
  6.   __in       DWORD dwCreationFlags, 
  7.   __out_opt  LPDWORD lpThreadId 
  8. ); 

第一個參數是安全屬性,指向一個LPSECURITY_ATTRIBUTES類型的結構體,一般設為NULL;

第二個參數是線程的堆棧大小,如果不是內存特別緊張的話,就設為0,表示windows將動態調整堆棧的大小;

第三個參數是指向線程函數的指針,其實就是函數名。函數名隨便起,但是在聲名函數時必須要遵守形式

  1. DWORD WINAPI ThreadProc(LPVOID lpParameter)  

否則就無法成功調用;

第四個參數是向線程函數傳遞的參數,不傳遞時就設為NULL;

第五個參數是線程標志,有兩個可取值:

     1). CREATE_SUSPENDED,表示創建後立即掛起

     2). 0,表示正常創建,創建後立刻運行

第六個參數用來保存新建線程的ID,如果不需要處理線程ID的話,則可傳入NULL。

返回值是線程的句柄。

運行時效果如下

這個程序其實是有風險的,風險有二:

    1). 在MFC程序中,應該盡量使用AfxBeginThread方法來創建線程。

    2). 如果我不停地按start,一會內存就用光了=。=

2的解決方法就不上了,無非是使用標志位,線程沒跑完之前不再創建新的線程。

來說說AfxBeginThread。這是MFC中的比較安全的線程創建方法。函數原型如下:

  1. CWinThread* AfxBeginThread( 
  2.    AFX_THREADPROC pfnThreadProc, 
  3.    LPVOID pParam, 
  4.    int nPriority = THREAD_PRIORITY_NORMAL, 
  5.    UINT nStackSize = 0, 
  6.    DWORD dwCreateFlags = 0, 
  7.    LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL  
  8. ); 
  9. CWinThread* AfxBeginThread( 
  10.    CRuntimeClass* pThreadClass, 
  11.    int nPriority = THREAD_PRIORITY_NORMAL, 
  12.    UINT nStackSize = 0, 
  13.    DWORD dwCreateFlags = 0, 
  14.    LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL  
  15. ); 

有兩個可以重載的函數,常用的是第一個。也能看出來,第一個函數與CreateThread()的參數其實是差不多的,只不過順序不太一樣。需要注意的是第二個重載函數,參數一是CRuntimeClass * pThreadClass,CRuntimeClass是個結構體,MSDN裡的解釋是“The RUNTIME_CLASS of an object derived from CWinThread.”為此我特意看了一下AfxBeginThread的源代碼,其中有如下一行:

  1. ASSERT(pThreadClass->IsDerivedFrom(RUNTIME_CLASS(CWinThread))); 

表明RUNTIME_CLASS是個宏定義。

  1. #define RUNTIME_CLASS(class_name) (class_name::GetThisClass()) 

也就是用這個宏將線程類指針轉換為指向CRuntimeClass的對象指針。

那麼新的線程創建語句就變為了:

  1. CWinThread * m_thread;  // m_thread為成員變量
  2. m_thread = AfxBeginThread(ThreadProc, this); 

而且需要將線程函數的聲明修改一下:

  1. UINT ThreadProc(LPVOID lpParameter) 

線程執行的中間是可以暫停的,使用DWORD CWinThread::SuspendThread()函數即可。暫停後可以使用DWORD CWinThread::ResumeThread()函數使線程恢復運行。

這是基本用法,至於一些高級點兒的東西,明兒繼續。

PS:正所謂懂得越多就發現懂得越少,今天搜資料,又搜出好多沒聽過的東西=。=,全部記在本子上,逐個消滅之。。

PSS:下一個目標,看明白與這個網頁相關聯的東西。。http://en.wikipedia.org/wiki/Thread_(computing)

PSSS:這玩意兒真形象。。

 

本文出自 “正面旺得福反面泰瑞寶” 博客,請務必保留此出處http://serious.blog.51cto.com/242085/857669

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved