青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

yehao's Blog

多線程編程之四——線程的同步

Part of the red marker to add by YeHao,Order oneself to better understand.

八、線程的同步

  雖然多線程能給我們帶來好處,但是也有不少問題需要解決。例如,對于像磁盤驅動器這樣獨占性系統資源,由于線程可以執行進程的任何代碼段,且線程的運行是由系統調度自動完成的,具有一定的不確定性,因此就有可能出現兩個線程同時對磁盤驅動器進行操作,從而出現操作錯誤;又例如,對于銀行系統的計算機來說,可能使用一個線程來更新其用戶數據庫,而用另外一個線程來讀取數據庫以響應儲戶的需要,極有可能讀數據庫的線程讀取的是未完全更新的數據庫,因為可能在讀的時候只有一部分數據被更新過。

  使隸屬于同一進程的各線程協調一致地工作稱為線程的同步。MFC提供了多種同步對象,下面我們只介紹最常用的四種:

  • 臨界區(CCriticalSection)
  • 事件(CEvent)
  • 互斥量(CMutex)
  • 信號量(CSemaphore)
     

通過這些類,我們可以比較容易地做到線程同步。

A、使用 CCriticalSection 類

  當多個線程訪問一個獨占性共享資源時,可以使用“臨界區”對象。任一時刻只有一個線程可以擁有臨界區對象,擁有臨界區的線程可以訪問被保護起來的資源或代碼段,其他希望進入臨界區的線程將被掛起等待,直到擁有臨界區的線程放棄臨界區時為止,這樣就保證了不會在同一時刻出現多個線程訪問共享資源。

CCriticalSection類的用法非常簡單,步驟如下:
 

  1. 定義CCriticalSection類的一個全局對象(以使各個線程均能訪問),如CCriticalSection critical_section;
  2. 在訪問需要保護的資源或代碼之前,調用CCriticalSection類的成員Lock()獲得臨界區對象:
    critical_section.Lock();
        
    在線程中調用該函數來使線程獲得它所請求的臨界區。如果此時沒有其它線程占有臨界區對象,則調用Lock()的線程獲得臨界區;否則,線程將被掛起,并放入到一個系統隊列中等待,直到當前擁有臨界區的線程釋放了臨界區時為止。
  3. 訪問臨界區完畢后,使用CCriticalSection的成員函數Unlock()來釋放臨界區:
    critical_section.Unlock();
        
    再通俗一點講,就是線程A執行到critical_section.Lock();語句時,如果其它線程(B)正在執行critical_section.Lock();語句后且critical_section. Unlock();語句前的語句時,線程A就會等待,直到線程B執行完critical_section. Unlock();語句,線程A才會繼續執行。

下面再通過一個實例進行演示說明。


例程8 MultiThread8

  1. 建立一個基于對話框的工程MultiThread8,在對話框IDD_MULTITHREAD8_DIALOG中加入兩個按鈕和兩個編輯框控件,兩個按鈕的ID分別為IDC_WRITEW和IDC_WRITED,標題分別為“寫‘W’”和“寫‘D’”;兩個編輯框的ID分別為IDC_W和IDC_D,屬性都選中Read-only;
  2. 在MultiThread8Dlg.h文件中聲明兩個線程函數:
    UINT WriteW(LPVOID pParam);
        UINT WriteD(LPVOID pParam);
        
  3. 使用ClassWizard分別給IDC_W和IDC_D添加CEdit類變量m_ctrlW和m_ctrlD;
  4. 在MultiThread8Dlg.cpp文件中添加如下內容:

    為了文件中能夠正確使用同步類,在文件開頭添加:
    #include "afxmt.h"
        
    定義臨界區和一個字符數組,為了能夠在不同線程間使用,定義為全局變量:
    CCriticalSection critical_section;
        char g_Array[10];
        
    添加線程函數:
    UINT WriteW(LPVOID pParam)
        {
        CEdit *pEdit=(CEdit*)pParam;
        pEdit->SetWindowText("");
        critical_section.Lock();
        //鎖定臨界區,其它線程遇到critical_section.Lock();語句時要等待
        //直至執行critical_section.Unlock();語句
        for(int i=0;i<10;i++)
        {
        g_Array[i]=''W'';
        pEdit->SetWindowText(g_Array);
        Sleep(1000);
        }
        critical_section.Unlock();
        return 0;
        }
        UINT WriteD(LPVOID pParam)
        {
        CEdit *pEdit=(CEdit*)pParam;
        pEdit->SetWindowText("");
        critical_section.Lock();
        //鎖定臨界區,其它線程遇到critical_section.Lock();語句時要等待
        //直至執行critical_section.Unlock();語句
        for(int i=0;i<10;i++)
        {
        g_Array[i]=''D'';
        pEdit->SetWindowText(g_Array);
        Sleep(1000);
        }
        critical_section.Unlock();
        return 0;
        }
  5. 分別雙擊按鈕IDC_WRITEW和IDC_WRITED,添加其響應函數:
    void CMultiThread8Dlg::OnWritew()
        {
        CWinThread *pWriteW=AfxBeginThread(WriteW,
        &m_ctrlW,
        THREAD_PRIORITY_NORMAL,
        0,
        CREATE_SUSPENDED);
        pWriteW->ResumeThread();
        }
        void CMultiThread8Dlg::OnWrited()
        {
        CWinThread *pWriteD=AfxBeginThread(WriteD,
        &m_ctrlD,
        THREAD_PRIORITY_NORMAL,
        0,
        CREATE_SUSPENDED);
        pWriteD->ResumeThread();
        }
    由于代碼較簡單,不再詳述。編譯、運行該例程,您可以連續點擊兩個按鈕,觀察體會臨界類的作用。

B、使用 CEvent 類

  CEvent 類提供了對事件的支持。事件是一個允許一個線程在某種情況發生時,喚醒另外一個線程的同步對象。例如在某些網絡應用程序中,一個線程(記為A)負責監聽通訊端口,另外一個線程(記為B)負責更新用戶數據。通過使用CEvent 類,線程A可以通知線程B何時更新用戶數據。每一個CEvent 對象可以有兩種狀態:有信號狀態和無信號狀態。線程監視位于其中的CEvent 類對象的狀態,并在相應的時候采取相應的操作。
  在MFC中,CEvent 類對象有兩種類型:人工事件和自動事件。一個自動CEvent 對象在被至少一個線程釋放后會自動返回到無信號狀態;而人工事件對象獲得信號后,釋放可利用線程,但直到調用成員函數ReSetEvent()才將其設置為無信號狀態。在創建CEvent 類的對象時,默認創建的是自動事件。 CEvent 類的各成員函數的原型和參數說明如下:

1、CEvent(BOOL bInitiallyOwn=FALSE,
BOOL bManualReset=FALSE,
LPCTSTR lpszName=NULL,
LPSECURITY_ATTRIBUTES lpsaAttribute=NULL);

 

  • bInitiallyOwn:指定事件對象初始化狀態,TRUE為有信號,FALSE為無信號;
  • bManualReset:指定要創建的事件是屬于人工事件還是自動事件。TRUE為人工事件,FALSE為自動事件;
  • 后兩個參數一般設為NULL,在此不作過多說明。
2、BOOL CEvent::SetEvent();
  將 CEvent 類對象的狀態設置為有信號狀態。如果事件是人工事件,則 CEvent 類對象保持為有信號狀態,直到調用成員函數ResetEvent()將 其重新設為無信號狀態時為止。如果CEvent 類對象為自動事件,則在SetEvent()將事件設置為有信號狀態后,CEvent 類對象由系統自動重置為無信號狀態。

如果該函數執行成功,則返回非零值,否則返回零。
3、BOOL CEvent::ResetEvent();
  該函數將事件的狀態設置為無信號狀態,并保持該狀態直至SetEvent()被調用時為止。由于自動事件是由系統自動重置,故自動事件不需要調用該函數。如果該函數執行成功,返回非零值,否則返回零。我們一般通過調用WaitForSingleObject函數來監視事件狀態。前面我們已經介紹了該函數。由于語言描述的原因,CEvent 類的理解確實有些難度,但您只要通過仔細玩味下面例程,多看幾遍就可理解。

例程9 MultiThread9

  1. 建立一個基于對話框的工程MultiThread9,在對話框IDD_MULTITHREAD9_DIALOG中加入一個按鈕和兩個編輯框控件,按鈕的ID為IDC_WRITEW,標題為“寫‘W’”;兩個編輯框的ID分別為IDC_W和IDC_D,屬性都選中Read-only;
  2. 在MultiThread9Dlg.h文件中聲明兩個線程函數:
    UINT WriteW(LPVOID pParam);
        UINT WriteD(LPVOID pParam);
        
  3. 使用ClassWizard分別給IDC_W和IDC_D添加CEdit類變量m_ctrlW和m_ctrlD;
  4. 在MultiThread9Dlg.cpp文件中添加如下內容:

    為了文件中能夠正確使用同步類,在文件開頭添加

    #include "afxmt.h"
        
    定義事件對象和一個字符數組,為了能夠在不同線程間使用,定義為全局變量。
    //CEvent eventWriteD;//默認為無信號狀態
    CEvent eventWriteD(TRUE);
    char g_Array[10];
    添加線程函數:
    UINT WriteW(LPVOID pParam)
        {
        CEdit *pEdit=(CEdit*)pParam;
        pEdit->SetWindowText("");
        WaitForSingleObject(eventWriteD.m_hObject,INFINITE);//函數返回時事件自動重置為無信號狀態
    for(int i=0;i<10;i++) { g_Array[i]=''W''; pEdit->SetWindowText(g_Array); Sleep(1000); } eventWriteD.SetEvent();//將事件置為有信號狀態,使其他線程可以獲得有信號狀態 return 0; } UINT WriteD(LPVOID pParam) { CEdit *pEdit=(CEdit*)pParam; pEdit->SetWindowText(""); WaitForSingleObject(eventWriteD.m_hObject,INFINITE);//當事件為無信號狀態時WaitForSingleObject會阻塞線程,走到事件有信號 for(int i=0;i<10;i++) { g_Array[i]=''D''; pEdit->SetWindowText(g_Array); Sleep(1000); }
    eventWriteD.SetEvent(); return 0; }
  5.   仔細分析這兩個線程函數, 您就會正確理解CEvent 類。線程WriteD執行到 WaitForSingleObject(eventWriteD.m_hObject,INFINITE);處等待,直到事件eventWriteD為有信號該線程才往下執行,因為eventWriteD對象是自動事件,則當WaitForSingleObject()返回時,系統自動把eventWriteD對象重置為無信號狀態。
  6. 雙擊按鈕IDC_WRITEW,添加其響應函數:
    void CMultiThread9Dlg::OnWritew()
        {
        CWinThread *pWriteW=AfxBeginThread(WriteW,
        &m_ctrlW,
        THREAD_PRIORITY_NORMAL,
        0,
        CREATE_SUSPENDED);
        pWriteW->ResumeThread();
        CWinThread *pWriteD=AfxBeginThread(WriteD,
        &m_ctrlD,
        THREAD_PRIORITY_NORMAL,
        0,
        CREATE_SUSPENDED);
        pWriteD->ResumeThread();
        }
    編譯并運行程序,單擊“寫‘W’”按鈕,體會事件對象的作用。

C、使用CMutex 類

  互斥對象與臨界區對象很像.互斥對象與臨界區對象的不同在于:互斥對象可以在進程間使用,而臨界區對象只能在同一進程的各線程間使用。當然,互斥對象也可以用于同一進程的各個線程間,但是在這種情況下,使用臨界區會更節省系統資源,更有效率。

D、使用CSemaphore 類

  當需要一個計數器來限制可以使用某個線程的數目時,可以使用“信號量”對象。CSemaphore 類的對象保存了對當前訪問某一指定資源的線程的計數值,該計數值是當前還可以使用該資源的線程的數目。如果這個計數達到了零,則所有對這個CSemaphore 類對象所控制的資源的訪問嘗試都被放入到一個隊列中等待,直到超時或計數值不為零時為止。一個線程被釋放已訪問了被保護的資源時,計數值減1;一個線程完成了對被控共享資源的訪問時,計數值增1。這個被CSemaphore 類對象所控制的資源可以同時接受訪問的最大線程數在該對象的構建函數中指定。

CSemaphore 類的構造函數原型及參數說明如下:

CSemaphore (LONG lInitialCount=1,
LONG lMaxCount=1,
LPCTSTR pstrName=NULL,
LPSECURITY_ATTRIBUTES lpsaAttributes=NULL);
  • lInitialCount:信號量對象的初始計數值,即可訪問線程數目的初始值;
  • lMaxCount:信號量對象計數值的最大值,該參數決定了同一時刻可訪問由信號量保護的資源的線程最大數目;
  • 后兩個參數在同一進程中使用一般為NULL,不作過多討論;

  在用CSemaphore 類的構造函數創建信號量對象時要同時指出允許的最大資源計數和當前可用資源計數。一般是將當前可用資源計數設置為最大資源計數,每增加一個線程對共享資源的訪問,當前可用資源計數就會減1,只要當前可用資源計數是大于0的,就可以發出信號量信號。但是當前可用計數減小到0時,則說明當前占用資源的線程數已經達到了所允許的最大數目,不能再允許其它線程的進入,此時的信號量信號將無法發出。線程在處理完共享資源后,應在離開的同時通過ReleaseSemaphore()函數將當前可用資源數加1。

下面給出一個簡單實例來說明 CSemaphore 類的用法。

例程10 MultiThread10

  1. 建立一個基于對話框的工程MultiThread10,在對話框IDD_MULTITHREAD10_DIALOG中加入一個按鈕和三個編輯框控件,按鈕的ID為IDC_START,標題為“同時寫‘A’、‘B’、‘C’”;三個編輯框的ID分別為IDC_A、IDC_B和IDC_C,屬性都選中Read-only;
  2. 在MultiThread10Dlg.h文件中聲明兩個線程函數:
    UINT WriteA(LPVOID pParam);
        UINT WriteB(LPVOID pParam);
        UINT WriteC(LPVOID pParam); 
  3. 使用ClassWizard分別給IDC_A、IDC_B和IDC_C添加CEdit類變量m_ctrlA、m_ctrlB和m_ctrlC;
  4. 在MultiThread10Dlg.cpp文件中添加如下內容:

    為了文件中能夠正確使用同步類,在文件開頭添加:

    #include "afxmt.h"
        
    定義信號量對象和一個字符數組,為了能夠在不同線程間使用,定義為全局變量:
    CSemaphore semaphoreWrite(2,2); //資源最多訪問線程2個,當前可訪問線程數2個,應該改為(1,1)才能實現同步的效果
        char g_Array[10]; 

    添加三個線程函數:

    UINT WriteA(LPVOID pParam)
        {
        CEdit *pEdit=(CEdit*)pParam;
        pEdit->SetWindowText("");
        WaitForSingleObject(semaphoreWrite.m_hObject,INFINITE);
        CString str;
        for(int i=0;i<10;i++)
        {
        pEdit->GetWindowText(str);
        g_Array[i]=''A'';
        str=str+g_Array[i];
        pEdit->SetWindowText(str);
        Sleep(1000);
        }
        ReleaseSemaphore(semaphoreWrite.m_hObject,1,NULL);
        return 0;
        }
        UINT WriteB(LPVOID pParam)
        {
        CEdit *pEdit=(CEdit*)pParam;
        pEdit->SetWindowText("");
        WaitForSingleObject(semaphoreWrite.m_hObject,INFINITE);
        CString str;
        for(int i=0;i<10;i++)
        {
        pEdit->GetWindowText(str);
        g_Array[i]=''B'';
        str=str+g_Array[i];
        pEdit->SetWindowText(str);
        Sleep(1000);
        }
        ReleaseSemaphore(semaphoreWrite.m_hObject,1,NULL);
        return 0;
        }
        UINT WriteC(LPVOID pParam)
        {
        CEdit *pEdit=(CEdit*)pParam;
        pEdit->SetWindowText("");
        WaitForSingleObject(semaphoreWrite.m_hObject,INFINITE);
        for(int i=0;i<10;i++)
        {
        g_Array[i]=''C'';
        pEdit->SetWindowText(g_Array);
        Sleep(1000);
        }
        ReleaseSemaphore(semaphoreWrite.m_hObject,1,NULL);
        return 0;
        }
        
    這三個線程函數不再多說。在信號量對象有信號的狀態下,線程執行到WaitForSingleObject語句處繼續執行,同時可用線程數減1;若線程執行到WaitForSingleObject語句時信號量對象無信號,線程就在這里等待,直到信號量對象有信號線程才往下執行。
  5. 雙擊按鈕IDC_START,添加其響應函數:
    void CMultiThread10Dlg::OnStart()
        {
        CWinThread *pWriteA=AfxBeginThread(WriteA,
        &m_ctrlA,
        THREAD_PRIORITY_NORMAL,
        0,
        CREATE_SUSPENDED);
        pWriteA->ResumeThread();
        CWinThread *pWriteB=AfxBeginThread(WriteB,
        &m_ctrlB,
        THREAD_PRIORITY_NORMAL,
        0,
        CREATE_SUSPENDED);
        pWriteB->ResumeThread();
        CWinThread *pWriteC=AfxBeginThread(WriteC,
        &m_ctrlC,
        THREAD_PRIORITY_NORMAL,
        0,
        CREATE_SUSPENDED);
        pWriteC->ResumeThread();
        }
        

好吧,多線程編程就介紹到這里,希望本文能對您有所幫助。

posted on 2011-04-25 17:31 厚積薄發 閱讀(169) 評論(0)  編輯 收藏 引用 所屬分類: Windows編程

導航

<2025年9月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

統計

常用鏈接

留言簿

隨筆分類

文章分類

文章檔案

搜索

最新評論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲欧美日本国产专区一区| 国产视频综合在线| 亚洲国产精品久久91精品| 国产精品日韩二区| 国产美女高潮久久白浆| 国产午夜精品久久久久久免费视| 国产一区二区日韩精品欧美精品| 国产一区二区三区免费在线观看| 韩国三级在线一区| 亚洲人成免费| 亚洲欧美日韩综合| 久久免费黄色| 欧美激情区在线播放| av72成人在线| 久久精品日韩欧美| 欧美日韩精品福利| 国模吧视频一区| 99精品热6080yy久久| 欧美亚洲一区二区三区| 欧美成人精品一区二区三区| 9色国产精品| 另类激情亚洲| 国产精品视频一区二区三区| 亚洲国产婷婷| 午夜视频在线观看一区二区三区| 久久精品中文字幕免费mv| 亚洲国产精品一区| 一区二区三区免费观看| 欧美在线视频在线播放完整版免费观看 | 久久久久久久久蜜桃| 亚洲欧洲综合另类| 欧美一区二区在线免费播放| 欧美日本乱大交xxxxx| 国产一区二区三区在线免费观看 | 亚洲国产精品尤物yw在线观看| 亚洲视频www| 欧美成人亚洲成人| 午夜欧美精品| 国产精品极品美女粉嫩高清在线| 亚洲国产一区在线| 久久久久久午夜| 亚洲性视频h| 欧美日韩国产首页在线观看| 亚洲高清123| 六月婷婷久久| 久久国产精品久久w女人spa| 国产精品一区二区三区四区五区| 一区二区日韩欧美| 亚洲人成7777| 欧美国产免费| 久久婷婷成人综合色| 一区二区三区国产在线| 欧美黑人多人双交| 亚洲激情欧美| 欧美a级在线| 美女露胸一区二区三区| 国产一区视频网站| 欧美影院一区| 午夜视频在线观看一区| 国产精品一区在线观看你懂的| 亚洲一区二区三区四区视频| 亚洲精品中文字| 欧美日韩一区二区免费在线观看| 日韩视频―中文字幕| 亚洲日本va午夜在线电影| 欧美暴力喷水在线| 99亚洲一区二区| 一区二区av| 国产欧美日韩在线播放| 久久久999成人| 久久久www免费人成黑人精品 | 国产婷婷色一区二区三区| 欧美亚洲一区| 欧美中文字幕不卡| 在线播放豆国产99亚洲| 欧美高清在线| 欧美日韩国产一区精品一区| 亚洲一区二区动漫| 亚洲欧美日韩区| 精品不卡一区| 亚洲精品视频一区二区三区| 国产精品国产三级国产专区53| 欧美专区第一页| 老鸭窝毛片一区二区三区| av不卡免费看| 西瓜成人精品人成网站| 亚洲国产精品va| 9l国产精品久久久久麻豆| 国产日韩综合| 亚洲福利视频专区| 国产精品久久久久一区二区| 老司机久久99久久精品播放免费 | 欧美在线视频a| 亚洲精品久久久久| 亚洲图片欧洲图片日韩av| 国产一区二区视频在线观看 | 亚洲经典在线| 在线亚洲激情| 在线观看欧美视频| 一区二区欧美激情| 一区二区在线观看av| 99国产精品久久久久久久成人热| 国产一区二区三区四区| 日韩视频在线免费| 影音先锋中文字幕一区| 中文精品视频一区二区在线观看| 亚洲精品一区在线观看| 欧美日韩午夜在线视频| 久久久亚洲国产天美传媒修理工 | 免费欧美在线视频| 亚洲欧美日韩中文视频| 欧美激情亚洲一区| 麻豆av一区二区三区久久| 国产精品卡一卡二| 亚洲精品国产精品国自产在线| 国产一区二区三区视频在线观看 | 亚洲永久免费| 欧美精品一区二区三区一线天视频| 久久都是精品| 国产精品久久国产精品99gif| 亚洲电影免费在线观看| 黄色国产精品一区二区三区| 亚洲伊人网站| 亚洲在线视频观看| 欧美日韩一区二区在线播放| 亚洲国产毛片完整版| 亚洲高清免费在线| 久久久久女教师免费一区| 久久精品人人爽| 国产日韩高清一区二区三区在线| 一区二区三区欧美激情| 一本大道av伊人久久综合| 欧美福利一区二区| 亚洲激情成人| 日韩视频在线观看一区二区| 欧美成人黄色小视频| 亚洲成人直播| 亚洲国产日韩一级| 欧美sm视频| 亚洲三级电影全部在线观看高清| 亚洲欧洲精品成人久久奇米网| 久热精品在线视频| 亚洲电影专区| 一本久久综合| 国产精品videossex久久发布| 亚洲小视频在线观看| 欧美在线视频一区| 伊人男人综合视频网| 欧美gay视频激情| 一本色道久久加勒比88综合| 午夜欧美不卡精品aaaaa| 国产欧美日韩视频在线观看 | 欧美日韩国产不卡| 一区二区三区四区国产| 欧美一级淫片播放口| 国产日韩亚洲欧美精品| 久久精品国产免费观看| 欧美国产综合视频| 亚洲视频在线二区| 国产色视频一区| 久热精品视频在线免费观看| 亚洲精品国产精品久久清纯直播| 亚洲女性裸体视频| 亚洲天天影视| 国产日韩欧美在线视频观看| 久久福利视频导航| 欧美激情网友自拍| 亚洲欧美日韩一区二区三区在线观看| 国产精品手机视频| 久久一日本道色综合久久| 亚洲欧洲另类国产综合| 午夜日韩电影| 亚洲国产视频直播| 国产精自产拍久久久久久| 老司机精品视频网站| 一区二区三区 在线观看视| 久久久久在线观看| 在线亚洲高清视频| 依依成人综合视频| 欧美视频中文在线看| 久久久久久久999| 夜夜夜精品看看| 欧美高清视频一区二区| 欧美一区影院| 亚洲视频国产视频| 91久久久久久久久久久久久| 国产欧美日韩精品一区| 欧美日韩免费在线观看| 久久久另类综合| 亚洲欧美精品伊人久久| 亚洲精品乱码久久久久久蜜桃91| 久久五月激情| 欧美中文在线字幕| 亚洲一区二区三区四区五区黄| 亚洲黄色在线看| 精品动漫一区二区| 国产性色一区二区| 国产精品丝袜白浆摸在线| 欧美日本不卡视频| 欧美成人性生活|