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