[并发并行]_[C/C++]_[使用线程本地存储Thread Local Storage(TLS)-win32和pthread比较]


场景:

1.  需要统计某个线程的对象上创建的个数.

2. 当创建的堆空间需要根据线程需要创建和结束时销毁时.

3. 因为范围是线程只能看到自己的存储数据,所以不需要临界区或互斥量来维护自己的堆内存. 加入如果用全局std::map实现,那么必须在put和get时加锁,这是很损耗资源的.

4. 可以用在维护一个连接,比如socket,database连接.


说明:

1. Java也有自己的线程本地存储ThreadLocal

2. pthread的win32版本: http://sourceware.org/pthreads-win32/


例子test_TSL.cpp:

#include "stdafx.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h> 
#include <windows.h> 
#include "pthread.h"

#define THREADCOUNT 4 
DWORD dwTlsIndex; 
VOID ErrorExit(const char*); 

static pthread_barrier_t barrier  = NULL;
static pthread_once_t random_is_initialized = PTHREAD_ONCE_INIT;
static pthread_key_t key;

VOID CommonFunc(VOID) 
{ 
   LPVOID lpvData; 
 
// Retrieve a data pointer for the current thread. 
 
   lpvData = TlsGetValue(dwTlsIndex); 
   if ((lpvData == 0) && (GetLastError() != ERROR_SUCCESS)) 
      ErrorExit("TlsGetValue error"); 
 
// Use the data stored for the current thread. 
   int64_t* value = (int64_t*)lpvData;
   printf("common: thread %d: lpvData=%lx : value=%lld\n", 
      GetCurrentThreadId(), lpvData,*value); 
 
   Sleep(5000); 
} 
 
DWORD WINAPI ThreadFunc(VOID) 
{ 
   LPVOID lpvData; 
 
// Initialize the TLS index for this thread. 
 
   lpvData = (LPVOID) LocalAlloc(LPTR, 8); 
   if (! TlsSetValue(dwTlsIndex, lpvData)) 
      ErrorExit("TlsSetValue error"); 
   
   int64_t* value = (int64_t*)lpvData;
   *value = GetCurrentThreadId();
   printf("thread %d: lpvData=%lx\n", GetCurrentThreadId(), lpvData); 
 
   CommonFunc(); 
 
// Release the dynamic memory before the thread returns. 
 
   lpvData = TlsGetValue(dwTlsIndex); 
   if (lpvData != 0) 
      LocalFree((HLOCAL) lpvData); 
 
   return 0; 
}

void TestWin32TLS()
{
   DWORD IDThread; 
   HANDLE hThread[THREADCOUNT]; 
   int i; 
 
// Allocate a TLS index. 
 
   if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) 
      ErrorExit("TlsAlloc failed");

   //1. 注意,这个dwTlsIndex 并不是从0开始.
   printf("dwTlsIndex %ld\n",dwTlsIndex);
// Create multiple threads. 
 
   for (i = 0; i < THREADCOUNT; i++) 
   { 
      hThread[i] = CreateThread(NULL, // default security attributes 
         0,                           // use default stack size 
         (LPTHREAD_START_ROUTINE) ThreadFunc, // thread function 
         NULL,                    // no thread function argument 
         0,                       // use default creation flags 
         &IDThread);              // returns thread identifier 
 
   // Check the return value for success. 
      if (hThread[i] == NULL) 
         ErrorExit("CreateThread error\n"); 
   } 
 
   for (i = 0; i < THREADCOUNT; i++) 
      WaitForSingleObject(hThread[i], INFINITE); 
 
   TlsFree(dwTlsIndex);
}

void CommonFuncPthread(void) 
{
   void* lpvData = pthread_getspecific(key);
   int64_t* value = (int64_t*)lpvData;
   printf("common: thread %d: lpvData=%lx : value=%lld\n", 
      GetCurrentThreadId(), lpvData,*value); 
}

void* StartPthread(void* data)
{
	int64_t *buf = (int64_t*)malloc(256);
	*buf = GetCurrentThreadId();
	pthread_setspecific(key, buf);
	CommonFuncPthread();
	free(buf);
    pthread_barrier_wait(&barrier);

	return NULL;
}

//1.只调用一次,可以放在随意一个work thread执行函数里都可以,会随机找一个线程执行.
//2.类似win32的DLL_PROCESS_ATTACH只执行一次.

void TestPthreadTLS()
{
	pthread_key_create(&key, NULL);
	pthread_barrier_init(&barrier,NULL, THREADCOUNT + 1); 
	for(int i = 0; i< THREADCOUNT; ++i)
	{
		pthread_t t;
		pthread_create(&t,NULL,StartPthread,NULL);
		pthread_detach(t);
	}
	//1.等待其他线程执行完.
	pthread_barrier_wait(&barrier);
	pthread_key_delete(key);
}

DWORD main(VOID) 
{ 
   //1.win32TLS
   printf("TestWin32TLS\n");
   TestWin32TLS();
   //1.pthread TLS
   printf("TestPthreadTLS\n");
   TestPthreadTLS();
   return 0; 
} 
 
VOID ErrorExit (const char* lpszMessage) 
{ 
   fprintf(stderr, "%s\n", lpszMessage); 
   ExitProcess(0); 
}


.

输出:

TestWin32TLS
dwTlsIndex 26
thread 8452: lpvData=714f50
common: thread 8452: lpvData=714f50 : value=8452
thread 8460: lpvData=7153d0
common: thread 8460: lpvData=7153d0 : value=8460
thread 8456: lpvData=715610
common: thread 8456: lpvData=715610 : value=8456
thread 8464: lpvData=715190
common: thread 8464: lpvData=715190 : value=8464
TestPthreadTLS
common: thread 8520: lpvData=3b4eb0 : value=8520
common: thread 8512: lpvData=3b4ff0 : value=8512
common: thread 8516: lpvData=3b4eb0 : value=8516
common: thread 8524: lpvData=3b4ff0 : value=8524

参考:

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。