搜索
熱搜: 活動 交友 discuz
查看: 3292|回復: 0
打印 上一主題 下一主題

[教學] C++多執行緒(三)

[複製鏈接]
跳轉到指定樓層
1#
發表於 2007-8-14 04:47:37 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
多執行緒同步之Critical Sections(功能與Mutex相同,保證某一時刻只有一個執行緒能夠訪問共享資源,但是不是內核對象,所以訪問速度要比Mutex快,但是增沒有等待超時的功能,所以有可能會導致死鎖,使用時可以根據實際的情況選擇其一)
一 Critical Sections
1) 因為Critical Sections不是內核對象,所以只能用來統一進程內執行緒間的同步,不能用來多個不同進程間的執行緒的同步。
2) 如果在Critical Sections中間突然程序crash或是exit而沒有調用LeaveCriticalSection,則結果是改執行緒所對應的內核不能被釋放,該執行緒成為死執行緒。

3) 要比其他的內核對象的速度要快。

二使用CriticalSections的簡單實例,Stack在push的時候可以分為3個步驟,看下面的代碼,但是如果在第2步後此執行緒中斷切換到其他的執行緒,其他的執行緒push後再返回執行時,此執行緒繼續執行,這樣有可能剛才其他執行緒push就會被覆蓋了,在stack裡找不到了。(下面的代碼在debug下使用了CriticalSection,release下可能有問題)


#include <windows.h>
#include
<process.h>
#include
<stdio.h>
/**//////////////////////////////////////////////
//stack:
struct Node
{
   
struct Node *next;
   
int data;
}
;
struct Stack
{
   
struct Node *head;
#ifdef _DEBUG
    CRITICAL_SECTION critical_sec;
#endif

    Stack()
   
{
        head
= NULL;
#ifdef _DEBUG
        InitializeCriticalSection(
&critical_sec);
#endif
    }

   
~Stack()
   
{        
        
if(head != NULL)        
        
{
            
if(NULL == head->next)
            
{               
                delete head;
                head
= NULL;
            }

            
else
            
{
                Node
*p = head;
                Node
*q = head->next;

               
while(q != NULL)
               
{                    
                    delete p;
                    p
= q;
                    q
= q->next;
                }
;               
                delete p;
                p
= NULL;
            }
   
        }

#ifdef _DEBUG
        DeleteCriticalSection(
&critical_sec);
#endif
    }

   
void Push (int num)
   
{
        
//enter critical section、add a new node and then     
#ifdef _DEBUG
        EnterCriticalSection (
&critical_sec);
#endif
        Node
* node =
new Node();
        node
->next = head;
        node
->data = num;
        head
= node;  
        printf(
"Stack:%d\n",num);
        
//leave critical section
#ifdef _DEBUG
        LeaveCriticalSection (
&critical_sec);
#endif
    }

   
int Pop ()
   
{
#ifdef _DEBUG
        EnterCriticalSection (
&critical_sec);
#endif
        
int result =
0;
        
if(head!= NULL)
        
{
            result
= head->data;
            
if(head->next != NULL)
            
{
                Node
*temp = head->next;
                delete head;
                head
= temp;
            }

            
else
                head
= NULL;
        }
   
#ifdef _DEBUG
        LeaveCriticalSection (
&critical_sec);
#endif
        
return result;
    }

}
;

/**///////////////////////////////////////////////////////
//test:
unsigned  __stdcall Thread1(void
* pVoid)
{
    Stack
*stack = ((Stack*)pVoid);
   
for(int i =
200; i<220;++i)
   
{
        stack
->Push(i);
    }

   
return
1;        
}

unsigned __stdcall Thread2(
void
*pVoid)
{
    Stack
*stack = ((Stack*)pVoid);
   
for(int i =
0; i<20; ++i)
   
{
        stack
->Push(i);        
    }

   
return
1;
}

int main()
{
    Stack stack;
    stack.Push(
1000);
    stack.Push(
1000);

    HANDLE   hth1;
    unsigned  uiThread1ID;

    hth1
= (HANDLE)_beginthreadex( NULL,         // security

0,            // stack size
        Thread1,
        (
void*)&stack,           // arg list
        CREATE_SUSPENDED,  // so we can later call ResumeThread()

&uiThread1ID );

   
if ( hth1 ==
0 )
        printf(
"Failed to create thread 1\n");

    DWORD   dwExitCode;

    GetExitCodeThread( hth1、
&dwExitCode );  // should be STILL_ACTIVE = 0x00000103 = 259
    printf( "initial thread 1 exit code = %u\n"、dwExitCode );



    HANDLE   hth2;
    unsigned  uiThread2ID;

    hth2
= (HANDLE)_beginthreadex( NULL,         // security

0,            // stack size
        Thread2,
        (
void*)&stack,           // arg list
        CREATE_SUSPENDED,  // so we can later call ResumeThread()

&uiThread2ID );

   
if ( hth2 ==
0 )
        printf(
"Failed to create thread 2\n");

    GetExitCodeThread( hth2、
&dwExitCode );  // should be STILL_ACTIVE = 0x00000103 = 259
    printf( "initial thread 2 exit code = %u\n"、dwExitCode );  

    ResumeThread( hth1 );   
    ResumeThread( hth2 );

    WaitForSingleObject( hth1、INFINITE );
    WaitForSingleObject( hth2、INFINITE );

    GetExitCodeThread( hth1、
&dwExitCode );
    printf(
"thread 1 exited with code %u\n"、dwExitCode );

    GetExitCodeThread( hth2、
&dwExitCode );
    printf(
"thread 2 exited with code %u\n"、dwExitCode );

    CloseHandle( hth1 );
    CloseHandle( hth2 );   

    printf(
"Primary thread terminating.\n");
}



三 對Critical Section的封裝:
//////////////////////////////////////////////////////
// 方法一: Lock中的CritSect成員變量必須是引用類型。
class CritSect
{
public:
    friend
class Lock;
    CritSect()
{ InitializeCriticalSection(&_critSection); }
   
~CritSect() { DeleteCriticalSection(&_critSection); }
private:
   
void Acquire(){EnterCriticalSection(&_critSection);}
   
void Release(){LeaveCriticalSection(&_critSection);}

    CRITICAL_SECTION _critSection;
}
;

class Lock
{
public:
     Lock(CritSect
& critSect):_critSect(critSect) {    _critSect.Acquire(); }
     
~Lock(){_critSect.Release();}
private:
    CritSect
& _critSect;
}
;


//////////////////////////////////////////////////////
//方法二:
// MT-exclusive lock
class CLock {
public:
    CLock()            
{ InitializeCriticalSection (&m_criticalSection); }
   
void Lock ()        { EnterCriticalSection      (&m_criticalSection); }
   
void Unlock ()      { LeaveCriticalSection      (&m_criticalSection); }
   
virtual
~CLock()    { DeleteCriticalSection     (&m_criticalSection); }
private:
    CRITICAL_SECTION                    m_criticalSection;
}
;


// Scoped MT-exclusive lock
class CScopedLocker {
public:
    CScopedLocker (CLock
* t) : m_lock (t)      { m_lock->Lock();   }
   
~CScopedLocker()                            { m_lock->Unlock(); }
private:
    CLock
*                             m_lock;
}
;


對上面的2中封裝的調用都比較簡單,都是只有2行代碼。
CritSect sect;
Lock lock(sect);

CLock t;
CSCopedLocker st(&t);
下面的對封裝的測試代碼,保證了對g_n全局變量線上程1操作結束後執行緒2才可以操作。(下面的代碼因為對全局變量同步,所以需要申明含有CRITICAL_SECTION的類為全局)

#include<windows.h>
#include
<iostream>
using
namespace std;

/**///////////////////////////////////////////////////////
// ·&frac12;·‥O&raquo;£o

class CritSect
{
public:
    friend
class Lock;
    CritSect()
{ InitializeCriticalSection(&_critSection); }
   
~CritSect() { DeleteCriticalSection(&_critSection); }
private:
   
void Acquire(){EnterCriticalSection(&_critSection);}
   
void Release(){LeaveCriticalSection(&_critSection);}

    CRITICAL_SECTION _critSection;
}
;

class Lock
{
public:
     Lock(CritSect
& critSect):_critSect(critSect) {    _critSect.Acquire(); }
     
~Lock(){_critSect.Release();}
private:
    CritSect
& _critSect;
}
;

/**///////////////////////////////////////////////////////
//·&frac12;·‥&para;t£o

// MT-exclusive lock
class CLock {
public:
    CLock()            
{ InitializeCriticalSection (&m_criticalSection); }
   
void Lock ()        { EnterCriticalSection      (&m_criticalSection); }
   
void Unlock ()      { LeaveCriticalSection      (&m_criticalSection); }
   
virtual
~CLock()    { DeleteCriticalSection     (&m_criticalSection); }
private:
    CRITICAL_SECTION                    m_criticalSection;
}
;


// Scoped MT-exclusive lock
class CScopedLocker {
public:
    CScopedLocker (CLock
* t) : m_lock (t)      { m_lock->Lock();   }
   
~CScopedLocker()                            { m_lock->Unlock(); }
private:
    CLock
*                             m_lock;
}
;

// &para;OE&laquo;&frac34;OμA±aA&iquest;£&not;E1OACritical Section
// Declare the global variable
static
int  g_n;
CritSect sect;
//CLock t;



/**/////////Thread One Function///////////////////

UINT ThreadOne(LPVOID lParam)
{
   
    Lock
lock(sect);   
   
//CScopedLocker st(&t);
   
   
for(int i=0;i<100;i++)
   
{
        g_n
++;
        cout
<<
"Thread 1: "
<< g_n <<
"\n";
    }
        
   
// return the thread

return
0;
}



/**/////////Thread Two Function///////////////////

UINT ThreadTwo(LPVOID lParam)
{


    Lock
lock(sect);
   
//CScopedLocker st(&t);

   
for(int i=300;i<400;i++)
   
{
        g_n
++;
        cout
<<
"Thread 2: "<< g_n <<
"\n";
    }


   
// return the thread

return
0;
}



int main()
{

   
// Create the array of Handle
    HANDLE hThrd[2];   
   
//Thread ID's
    DWORD IDThread1、IDThread2;


   
// Create thredas use CreateThread function with NULL Security
    hThrd[0] = CreateThread(NULL、0,(LPTHREAD_START_ROUTINE) ThreadOne,(LPVOID)NULL,0,&IDThread1);      
    hThrd[
1] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) ThreadTwo,(LPVOID)NULL,0,&IDThread2);

   
// Wait for the main thread
    WaitForMultipleObjects(2,hThrd,TRUE,INFINITE);
   
   
return
0;
}



四 API列表:
            Critical-section function            Description                 DeleteCriticalSectionReleases all resources used by an unowned critical section object.         EnterCriticalSectionWaits for ownership of the specified critical section object.         InitializeCriticalSectionInitializes a critical section object.         InitializeCriticalSectionAndSpinCountInitializes a critical section object and sets the spin count for the critical section.         InitializeCriticalSectionExInitializes a critical section object with a spin count and optional flags.         LeaveCriticalSectionReleases ownership of the specified critical section object.         SetCriticalSectionSpinCountSets the spin count for the specified critical section.         TryEnterCriticalSectionAttempts to enter a critical section without blocking.

[ 本帖最後由 f66666602 於 2007-8-14 04:49 編輯 ]
您需要登錄後才可以回帖 登錄 | 註冊

本版積分規則

本論壇為非營利之網路平台,所有文章內容均為網友自行發表,不代表論壇立場!若涉及侵權、違法等情事,請告知版主處理。


Page Rank Check

廣告刊登  |   交換連結  |   贊助我們  |   服務條款  |   免責聲明  |   客服中心  |   中央分站

手機版|中央論壇

GMT+8, 2026-6-4 10:26 , Processed in 0.052112 second(s), 16 queries .

Powered by Discuz!

© 2005-2015 Copyrights. Set by YIDAS

快速回復 返回頂部 返回列表