程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> [並發並行]_[線程同步]_[C/C++實現單例模式分析]

[並發並行]_[線程同步]_[C/C++實現單例模式分析]

編輯:C++入門知識

[並發並行]_[線程同步]_[C/C++實現單例模式分析]


 

場景:

1. 很多情況下,我們需要實現一個類的單例模式,比如XXManager, 於是提供一個GetInstance()的函數. Java可以使用雙鎖來處理.C/C++也類似.

2. 提供GetInstance()的一個必要條件是必須是線程安全的, 否則會出現創建多個實例的情況. 更簡單的做法是在程序初始化時(Main線程)

調用一個CreateInstance()函數來創建, 但是如果這種單例對象多了的話, 這來CreateInstance調用也會增多, 如果忘記了調用還會直接崩潰.

3. 這裡實現了C/C++ 創建單例模式的方法, 一種是使用pthread庫創建的, 一種是使用win32 api創建.

 

4. Objc可以使用 dispatch_once來實現單例模式.

 

+(DhTaskManager*)getInstance
{
    static DhTaskManager *manager = nil;
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        manager = [DhTaskManager new];
    });
    return manager;
}

 


 

 

test.cpp

 

#include 
#include 
#include pthread.h
#include 
#include 

static int THREADCOUNT = 100;

class CSLock
{
public:
	CSLock()
	{
		InitializeCriticalSection(&cs_);
		std::cout << init lock! << std::endl;
	}

	~CSLock()
	{
		DeleteCriticalSection(&cs_);
	}
	operator PCRITICAL_SECTION() throw()  
	{
 		return &cs_;  
	}
private:
	
	CRITICAL_SECTION cs_;
};

// 實用場景1: 創建單例對象.
class UiDeviceManager
{
public:
	static void Destroy()
	{
		delete singleton_;
	}

	// 1.使用pthread_once來實現單例模式.
	static UiDeviceManager* GetInstance()
	{
		pthread_once(&random_is_initialized,init_instance);
		return singleton_;
	}

	// 1.使用Windows的原子鎖實現單例模式,不需要pthread庫
	static UiDeviceManager* GetInstance2()
	{
		static LONG done = 0;
		if (!InterlockedExchangeAdd(&done, 0)) 
		{
			EnterCriticalSection(cs_lock_);
			 if(!done)
			 {
			 	init_instance();
			 	done = 1;
			 }
			
			LeaveCriticalSection(cs_lock_);
		}
		return singleton_;
	}

private:
	static pthread_once_t random_is_initialized;
	static CSLock cs_lock_;

	static void init_instance ()
	{
		//測試,Sleep 3 seconds,驗證這個函數只被執行一次.
		//看有沒有線程進入這裡.
		//這裡只是測試
		Sleep(3000);
		std::cout << Sleep End << std::endl;
		static LONG locki_; //1. 這個變量只是測試用.
		InterlockedExchangeAdd(&locki_,1);
		assert(locki_ == 1);

		//只需要new
		singleton_ = new UiDeviceManager();
	}
	UiDeviceManager()
	{
		
	}
	static UiDeviceManager* singleton_;

};

CSLock UiDeviceManager::cs_lock_;
pthread_once_t UiDeviceManager::random_is_initialized = PTHREAD_ONCE_INIT;
UiDeviceManager* UiDeviceManager::singleton_ = NULL;
static pthread_barrier_t barrier  = NULL;


void* ThreadFunc(void* data)
{
	for (int i = 0; i < 10000; ++i)
	{
		// UiDeviceManager* udm = UiDeviceManager::GetInstance();
		UiDeviceManager* udm = UiDeviceManager::GetInstance2();
	}
	
	pthread_barrier_wait(&barrier);
	std::cout << ThreadFunc Finish << std::endl;
	return NULL;
}

void TestPthreadOnce()
{
	pthread_barrier_init(&barrier,NULL, THREADCOUNT + 1);

	for (int i = 0; i < THREADCOUNT; ++i)
	{
		pthread_t t;  
                pthread_create(&t,NULL,ThreadFunc,NULL);  
                pthread_detach(t);
	}
	std::cout << TestPthreadOnce Begin << std::endl;
	pthread_barrier_wait(&barrier);
	std::cout << TestPthreadOnce Finish << std::endl;
	pthread_barrier_destroy(&barrier);

	UiDeviceManager::Destroy();
}

int main(int argc, char const *argv[])
{
	TestPthreadOnce();
	return 0;
}


 

輸出:

 

init lock!
TestPthreadOnce Begin
Sleep End
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
TestPthreadOnce Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish
ThreadFunc Finish

參考:

 

http://www.douban.com/note/269039110/ 這個其實是有缺陷的!

pthread_once 函數源碼:

 

int
pthread_once (pthread_once_t * once_control, void (*init_routine) (void))
{
  if (once_control == NULL || init_routine == NULL)
    {
      return EINVAL;
    }
  
  if (!InterlockedExchangeAdd((LPLONG)&once_control->done, 0)) /* MBR fence */
    {
      ptw32_mcs_local_node_t node;

      ptw32_mcs_lock_acquire((ptw32_mcs_lock_t *)&once_control->lock, &node);

      if (!once_control->done)
	{

#ifdef _MSC_VER
#pragma inline_depth(0)
#endif

	  pthread_cleanup_push(ptw32_once_on_init_cancel, (void *)&node);
	  (*init_routine)();
	  pthread_cleanup_pop(0);

#ifdef _MSC_VER
#pragma inline_depth()
#endif

	  once_control->done = PTW32_TRUE;
	}

	ptw32_mcs_lock_release(&node);
    }

  return 0;

}				/* pthread_once */

 

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