多線程

 

    多線程共存於應用程序中是現代操作系統中的基本特徵和重要標誌。爲了提高程序的運行效率,在操作系統中提出了進程和線程的概念,在一個進程中可以包含多個線程,進程作爲資源分配的基本單位,線程作爲獨立運行和獨立調度的基本單位。既然提到了進程和線程,就涉及到進程(線程)的併發執行以及互斥對象的訪問。這些在網絡編程中都是十分重要的知識點。具體操作系統的知識就不做介紹了,下面通過實例詳細介紹網絡編程中的多線程技術。

    在程序運行時,操作系統會創建一個進程,同時就會產生一個主線程,我們可以在主線程中繼續創建線程,來完場我們制定的操作。

    1、創建線程,要用到創建線程的函數CreateThread(),這個函數的第三個參數制定了新創建線程的線程函數,該線程的所有操作都可以在該線程函數中完成。線程函數可以參看MSDN的詳細用法。線程函數的形式如下:DWORD WINAPI ThreadProc(LPVOID lpParameter);每一個線程都有一個線程句柄與之相關聯。

    2、線程同步:在一個進程中可以創建多個線程,這多個線程在需要訪問同一個資源時,肯定會發生爭用現象,在爭奪資源的過程中,加入第一個線程先訪問這一資源,並對其做了修改,在這個線程沒有執行完畢但時間片到了,第二個線程又訪問該資源,就可能得到錯誤的結果。這是非常嚴重的問題。爲了解決這一問題,引入了進程同步的概念,我們可以創建互斥對象來解決這一問題。創建互斥對象後,某線程只有得到互斥對象的訪問權後,纔可以訪問臨界資源,即使該線程的時間片到,如果該線程不釋放互斥對象的使用權,下一個線程由於獲得不到互斥對象,導致第二個線程無法訪問臨界資源。這就防止了線程在爭奪資源的過程中發生不可預知的錯誤。創建互斥對象的函數爲:CreateMutex(),該函數返回互斥對象的句柄。

    3、獲得臨界資源的訪問權:通過調用函數WaitForSingleObject()可以獲得臨界資源的訪問權,如果得到訪問權後,該線程不主動釋放該互斥對象,即使該線程的時間片到,下一個線程由於不能得到訪問權而不能訪問臨界資源。

    4、釋放互斥對象:該線程訪問臨界資源完畢,應該釋放互斥對象,讓其他線程有機會獲得訪問臨界資源的權利。釋放互斥對象可以調用函數ReleaseMutex()來實現。

注意:

1、互斥對象是和線程相關的,哪個線程需要訪問臨界資源,必須在該線程內部調用WaitForSingleObject()函數

2、線程執行完畢,應釋放互斥對象。必須是“誰擁有誰釋放”,必須在線程執行完畢之前釋放,不能在下一個線程的開始釋放。因爲互斥對象是和線程相關的,裏面維護有線程句柄來識別時哪個線程調用該函數。

3、“擁有幾次釋放幾次”:在互斥對象內部維護有一個計數器,可以統計獲得互斥對象的次數,只有計數器爲零時,下一個線程纔可以獲得該互斥對象。所以調用幾次獲得函數就需要釋放幾次。

下面通過一個火車售票系統的簡化模型來具體實現多線程技術的應用:

    假設共有100張火車票可以賣出,現在有兩個線程都可以賣票,爲了使賣票系統不會出現差錯,就需要用到互斥對象。示例代碼如下:

#include "stdafx.h"
#include <Windows.h>
#include <iostream>
using namespace std;

DWORD WINAPI ThreadProc1(
 LPVOID lpParameter   // thread data
 );
DWORD WINAPI ThreadProc2(
 LPVOID lpParameter   // thread data
 );

int tickets=100;
HANDLE hMutex;
int _tmain(int argc, _TCHAR* argv[])
{
 HANDLE hThread1;
 HANDLE hThread2;
 hThread1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);//創建線程1
 hThread2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);//創建線程2
 CloseHandle(hThread1);
 CloseHandle(hThread2);
 hMutex=CreateMutex(NULL,TRUE,NULL);//創建互斥對象
 ReleaseMutex(hMutex);//必須在主線程中釋放互斥對象
 Sleep(1000);//必須讓主線程暫停執行,如果主線程退出了,其他線程就不復存在了
 system("pause");
 return 0;
}

/****************************************************************

                                線程函數的實現

******************************************************************/

DWORD WINAPI ThreadProc1(LPVOID lpParameter)
{
 while (TRUE)
 {
  WaitForSingleObject(hMutex,INFINITE);
  if (tickets>0)
  {
   Sleep(1);
   cout<<"Thread1 sell tickets:"<<tickets--<<endl;
  }
  else
   break;
  ReleaseMutex(hMutex);
 }
 return 0;
}
DWORD WINAPI ThreadProc2(LPVOID lpParameter)
{
 while (TRUE)
 {
  WaitForSingleObject(hMutex,INFINITE);
  if (tickets>0)
  {
   Sleep(1);
   cout<<"Thread2 sell tickets:"<<tickets--<<endl;
  }
  else
   break;
  ReleaseMutex(hMutex);
 }
 return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章