C++ Programmer's Cookbook

{C++ 基础} {C++ 高级} {C#界面,C++核心算法} {设计模式} {C#基础}

C++多线程(三)

多线程同步之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 
*= head;
                Node 
*= 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;

//////////////////////////////////////////////////////
// ·½·¨Ò»£º

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;
}
;

// ¶ÔÈ«¾ÖµÄ±äÁ¿£¬Ê¹ÓÃCritical 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
DeleteCriticalSection Releases all resources used by an unowned critical section object.
EnterCriticalSection Waits for ownership of the specified critical section object.
InitializeCriticalSection Initializes a critical section object.
InitializeCriticalSectionAndSpinCount Initializes a critical section object and sets the spin count for the critical section.
InitializeCriticalSectionEx Initializes a critical section object with a spin count and optional flags.
LeaveCriticalSection Releases ownership of the specified critical section object.
SetCriticalSectionSpinCount Sets the spin count for the specified critical section.
TryEnterCriticalSection Attempts to enter a critical section without blocking.

posted on 2007-07-25 18:04 梦在天涯 阅读(6095) 评论(0)  编辑 收藏 引用 所属分类: CPlusPlus


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

EMail:itech001#126.com

导航

统计

  • 随笔 - 461
  • 文章 - 4
  • 评论 - 746
  • 引用 - 0

常用链接

随笔分类

随笔档案

收藏夹

Blogs

c#(csharp)

C++(cpp)

Enlish

Forums(bbs)

My self

Often go

Useful Webs

Xml/Uml/html

搜索

  •  

积分与排名

  • 积分 - 1795671
  • 排名 - 5

最新评论

阅读排行榜