转载 多线程开发时线程局部变量的使用

多线程开发时线程局部变量的使用

http://blog.csdn.net/zsxxsz/article/details/6284759

2011-03-28 22:37197人阅读评论(0)收藏举报

一、概述

  现在多核时代多线程开发越来越重要了,多线程相比于多进程有诸多优势(当然也有诸多劣势)。在早期C的库中,有许多函数是线程不安全的,因为内 部用到了静态变量,比如:char *strtok(char *s, const char *delim); 该函数内部就有一个静态指针,如果多个线程同时调用此函数时,可能就会出现奇怪的结果,当然也不是我们所想要的,现在LINUX对此函数功能有一个线程安 全版本的接口:char *strtok_r(char *s, const char *delim, char  **ptrptr),这就避免了多个线程同时访问的冲突问题。其实,如果保持 strtok()/2 接口不变,同时还要保证线程安全,还有一个解决办法,那就是采用线程局部变量。

  使用线程局部变量有两种使用方式,一个稍微麻烦些,一个比较简单,下面一一做个介绍(以LINUX为例)

二、线程局部变量的使用

比较麻烦些的使用方法用到的函数主要有三个:pthread_once(pthread_once_t*, void  (*init_routine)(void)), pthread_key_create()/2, pthread_setspecific()/2, pthread_getspecific()/1,其中 pthread_once 可以保证在整个进程空间init_routine函数仅被调用一次(它解决了多线程环境中使得互斥量和初始化代码都仅被初始化一次的问 题);pthread_key_create 的参数之一指一个析构函数指针,当某个线程终止时该析构函数将被调用,并用对于一个进程内的给定键,该函数只能被调用一 次;pthread_sespecific 和 pthread_getspecific 用来存放和获取与一个键关联的值。例子如下:

pthread_key_t key; pthread_once_t once = PTHREAD_ONCE_INIT;
static void destructor(void *ptr) {     free(ptr); }
void init_once(void) {     pthread_key_create(&key, destructor); }
static void *get_buf(void) {     pthread_once(&once, init_once);
    if ((ptr = pthread_getspecific(key)) == NULL) {         ptr = malloc(1024);         pthread_setspecific(key, ptr);     }     return (ptr); }
static void *thread_fn(void *arg) {     char *ptr = (char*) get_buf();
    sprintf(ptr, "hello world");     printf(">>%s/n", ptr);     return (NULL); }
void test(void) {     int   i, n = 10;     pthread_t tids[10];
    for (i = 0; i < n; i++) {         pthread_create(&tids[i], NULL, thread_fn, NULL);     }
    for (i = 0; i < n; i++) {         pthread_join(&tids[i], NULL);     } }

另外,还有一个更加简单使用线程局部变量的方法:__thread 修饰符, (在WIN32平台下需要用: __declspec(thread) 修饰符,WIN32的东东总得要多写几笔,呵呵),于是上述代码可以修改如下:

static void *get_buf(void) {     static __thread void *ptr = malloc(1024);     return (ptr); }
static void *thread_fn(void *arg) {     char *ptr = (char*) get_buf();
    sprintf(ptr, "hello world");     printf(">>%s/n", ptr);     return (NULL); }
void test(void) {     int   i, n = 10;     pthread_t tids[10];
    for (i = 0; i < n; i++) {         pthread_create(&tids[i], NULL, thread_fn, NULL);     }
    for (i = 0; i < n; i++) {         pthread_join(&tids[i], NULL);     } }

看到没有,这段代码比前面一个简单许多,但却有一个问题,它存在内存泄露问题,因为当线程退出时各个线程分配的动态内存(ptr = malloc(1024)) 并没有被释放。

三、用ACL线程接口操作线程局部变量

为了解决上述问题,ACL库中实现了线程局部变量的简单释放功能:acl_pthread_atexit_add(void *arg, void (*free_callback)(void*)),修改上述代码如下:

static void free_fn(void *ptr) {     free(ptr); }
static void *get_buf(void) {     static __thread void *ptr = malloc(1024);
    acl_pthread_atexit_add(ptr, free_fn);     return (ptr); }
static void *thread_fn(void *arg) {     char *ptr = (char*) get_buf();
    sprintf(ptr, "hello world");     printf(">>%s/n", ptr);     return (NULL); }
void test(void) {     int   i, n = 10;     pthread_t tids[10];
    for (i = 0; i < n; i++) {         acl_pthread_create(&tids[i], NULL, thread_fn, NULL);     }
    for (i = 0; i < n; i++) {         acl_pthread_join(&tids[i], NULL);     } }

ok, 一切问题得到解决。细心的读者会发现 pthread_create, pthread_join 前面都加了前缀: acl_, 这是因为 ACL库对线程库进行了封装,以适应不同平台下(UNIX、WIN32)下的使用,这个例子是跨平台的,WIN32下同样可用

时间: 2024-10-25 02:55:13

转载 多线程开发时线程局部变量的使用的相关文章

Java之多线程开发时多条件Condition接口的使用

转:http://blog.csdn.net/a352193394/article/details/39454157 我们在多线程开发中,可能会出现这种情况.就是一个线程需要另外一个线程满足某某条件才能继续运行,或者需 要其他线程满足好几个条件才能运行,对于这样的多条件的多线程并发,我们如何控制好各个线程之间的关系,使他们 能很好的处理冲突不至于相互出现问题呢,下面我们来介绍一下Java提供的Condition这个接口,这个接口很好的实现了 这种需求. 对于这个问题最经典的例子就是生产者消费者模

【多线程】Java线程面试题 Top 50(转载)

Java线程面试题 Top 50 原文链接:http://www.importnew.com/12773.html 本文由 ImportNew - 李 广 翻译自 javarevisited.欢迎加入Java小组.转载请参见文章末尾的要求. 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员的欢迎.大多数待遇丰厚的Java开发职位都要求开发者精通多线程技术并且有丰富的Java程序开发.调试.优化经验,所以线程

Java多线程开发系列之四:玩转多线程(线程的控制2)

在上节的线程控制(详情点击这里)中,我们讲解了线程的等待join().守护线程.本节我们将会把剩下的线程控制内容一并讲完,主要内容有线程的睡眠.让步.优先级.挂起和恢复.停止等. 废话不多说,我们直接进入正题:  3.线程睡眠  sleep() 所有介绍多线程开发的学习案例中,基本都有用到这个方法,这个方法的意思就是睡眠(是真的,请相信我...).好吧,如果你觉得不够具体,可以认为是让当前线程暂停一下,当前线程随之进入阻塞状态,当睡眠时间结束后,当前线程重新进入就绪状态,开始新一轮的抢占计划!

Java多线程开发系列之番外篇:事件派发线程---EventDispatchThread

事件派发线程是java Swing开发中重要的知识点,在安卓app开发中,也是非常重要的一点.今天我们在多线程开发中,穿插进来这个线程.分别从线程的来由.原理和使用方法三个方面来学习事件派发线程. 一.事件派发线程的前世今生 事件(Event)派发(Dispatch)线程(Thread)简写为EDT,也就是各个首字母的简写.在一些书或者博客里边也将其译为事件分发线程.事件调度线程.巴拉巴拉,总之,知道这些名字就行.笔者认为这里翻译成派发更准确点. 熟悉Swing和awt编程的小伙伴对事件派发线程

iOS多线程开发小demo4,线程的同步问题

// DYFViewController.m // 623-05-线程同步问题 // // Created by dyf on 14-6-23. // Copyright (c) 2014年 ___FULLUSERNAME___. All rights reserved. // #import "DYFViewController.h" @interface DYFViewController () @property (nonatomic, assign) int leftCount

linux_c 开发(6-1)多线程程序设计_线程基础

多线程 线程(thread)技术早在60年代就被提出来了,但真正应用多线程到操作系统中去,实在80年代中期,solaris是这方面的佼佼者.传统的UNIX也支持线程的概念,但是在一个进程中只允许有一个线程,这样多线程就意味着多进程.现在多线程技术已经被许多操作系统所支持,包括Windows/NT.Linux. 优点: 和进程相比,它是一种非常"节俭"的多任务操作方式.在linux系统下,启动一个新的进程必须分配给他独立的空间地址,建立众多的数据表来维护他的代码段.堆栈段和数据段,这是一

Windows多线程开发之并发线程程序研究

做为一名分布式服务器开发人员,在服务器开发领域.多线程开发和并发编程方面有自己的心得和经验,愿意分享给同仁,今讨论下Windows下线程并发程序开发. 下面用用两个线程实现一个简单的数组排序,演示了线程的基本用法. 原理是: 为了节省执行时间而添加并行,把问题划分为几个小问题,并分配给几个线程(分而治之),把问题划分成若干更小的单元,更容易在实现中创建并行逻辑.同时,在并行中使用系统资源能优化应用程序并提高其运行速度. #include "stdafx.h"  #include <

iOS开发多线程篇—创建线程

iOS开发多线程篇—创建线程 一.创建和启动线程简单说明 一个NSThread对象就代表一条线程 创建.启动线程 (1) NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; [thread start]; // 线程一启动,就会在线程thread中执行self的run方法 主线程相关用法 + (NSThread *)mainThread; // 获得主线程 -

关于CoreData和SQLite多线程访问时的线程安全问题

http://www.jianshu.com/p/95db3fc4deb3 关于CoreData和SQLite多线程访问时的线程安全问题 数据库读取操作一般都是多线程访问的.在对数据进行读取时,我们要保证其当前状态不能被修改,即读取时加锁,否则就会出现数据错误混乱.IOS中常用的两种数据持久化存储方式:CoreData和SQLite,两者都需要设置线程安全,在这里以FMDB来解释对SQLite的线程安全访问. 一:FMDB的线程安全:(以读取图片为例) 1.没有线程安全的执行方式: //****