Linux 下C语言多线程编程--线程数据

Trixie ·
更新时间:2024-09-21
· 506 次阅读

线程数据 在C语言编程中,我们都知道,数据共享往往是通过全局变量的方式,全局变量在单线程中不会有什么问题,但是在多线程情况下,如果多个线程都对这个全局变量进行读写操作,需要加锁进行保护,锁的代价其实是很大的。 在实际的使用中,很多时候我们只想要线程之间的全局变量,只能在该线程内访问,其他线程不能访问,这个时候就可以使用线程数据来实现,通过一个键值pthread_key_t来实现 键值的创建

函数原型:

/* Create a key value identifying a location in the thread-specific data area. Each thread maintains a distinct thread-specific data area. DESTR_FUNCTION, if non-NULL, is called with the value associated to that key when the key is destroyed. DESTR_FUNCTION is not called if the value associated is NULL when the key is destroyed. */ extern int pthread_key_create (pthread_key_t *__key, void (*__destr_function) (void *)) __THROW __nonnull ((1));

第一个参数:就是一个键值的指针
第二个参数:一个destructor函数,可以传NULL,如果不为空,当每个线程结束时,调用这个函数来释放绑定在这个键值上的内存快(这个参数很厉害,Demo中有使用说明)。

注:值得注意的是,这个函数往往和pthread_once()函数一起使用,目的是让这个键值只被创建一次

/* Guarantee that the initialization function INIT_ROUTINE will be called only once, even if pthread_once is executed several times with the same ONCE_CONTROL argument. ONCE_CONTROL must point to a static or extern variable initialized to PTHREAD_ONCE_INIT. The initialization functions might throw exception which is why this function is not marked with __THROW. */ extern int pthread_once (pthread_once_t *__once_control, void (*__init_routine) (void)) __nonnull ((1, 2));

第一个参数:是和key对应的一个标志,初始化为:PTHREAD_ONCE_INIT
第二个参数:初始化函数

键值的绑定和获取

绑定函数:

/* Store POINTER in the thread-specific data slot identified by KEY. */ extern int pthread_setspecific (pthread_key_t __key, const void *__pointer) __THROW ;

第一个参数:键值key
第二个参数:指向想要绑定的线程数据的指针

获取函数:

/* Return current value of the thread-specific data slot identified by KEY. */ extern void *pthread_getspecific (pthread_key_t __key) __THROW;

参数就是key,返回绑定的线程数据指针

Demo #include #include #include #include //声明一个全局变量key,该key对所有线程可见, //但是该key具体指向的内容各个线程不一样 //可以理解为一个二级指针 pthread_key_t key; //用于标识key,key只创建一次 pthread_once_t once_create = PTHREAD_ONCE_INIT; //自定义数据结构,用于测试 typedef struct ThreadData_t { pthread_t m_pid; char* m_threadName; } ThreadData; //释放线程自定义数据,即每个线程使用key具体指向的数据 //这里其实就是ThreadData static void free_thread_data(void* pData) { fprintf(stderr, "%s():addr= %p\n", __FUNCTION__, pData); free(pData); } //创建key static void create_my_key(void) { fprintf(stderr, "%s():called\n", __FUNCTION__); pthread_key_create(&key, free_thread_data); } static void test_get_thread_data(void) { ThreadData* pData = (ThreadData*)pthread_getspecific(key); fprintf(stderr, "%s():%s get data by key addr=%p\n", __FUNCTION__, pData->m_threadName, pData); return; } //线程函数routine static void* test_thread(void* thread_name) { //如果key没有被创建,就创建key,被创建了就不会再创建 pthread_once(&once_create, create_my_key); //申请一个线程数据结构,该数据只在该线程内可见,其他线程不可见, //但是该线程的其他函数可以获取到该数据 ThreadData* pData = (ThreadData*)malloc(sizeof(ThreadData)); if (pData == NULL) { fprintf(stderr, "%s():not enough memory\n", __FUNCTION__); return NULL; } pData->m_pid = pthread_self(); pData->m_threadName = (char*)thread_name; fprintf(stderr, "thread %s malloc data addr=%p\n", pData->m_threadName, pData); pthread_setspecific(key, pData); sleep(5); test_get_thread_data(); return NULL; } int main(int argc, char** argv) { pthread_t pid1, pid2; if (pthread_create(&pid1, NULL, test_thread, (void*)"test thread1") != 0) { fprintf(stderr, "create thread1 failed\n"); return -1; } if (pthread_create(&pid2, NULL, test_thread, (void*)"test thread2") != 0) { fprintf(stderr, "create thread2 failed\n"); return -1; } pthread_join(pid1, NULL); pthread_join(pid2, NULL); pthread_key_delete(key); return 0; } 执行结果

编译:gcc main.c -o main -lpthread
Demo结果


作者:一只泽杨



多线程编程 线程数 C语言 多线程 线程 Linux 数据

需要 登录 后方可回复, 如果你还没有账号请 注册新账号