linux 之 __thread & pthread_key_t

12 篇文章 0 订阅

linux 之 __thread & pthread_key_t

在说__thread之前,先来看看pthread_ket_t吧。

参考:http://blog.csdn.net/lmh12506/article/details/8452700

上面的博文说的比较通俗易懂。线程私有数据可以理解为线程内的全局变量。在线程内可以被所有函数访问,但是不能被其他线程的函数访问。

对于pthread_key_t的使用,最好使用RAII:

//博主参照muduo写的#include <pthread.h>
#include <vector>
#include <algorithm>
#include <iostream>
#include <boost/checked_delete.hpp>
template <typename T>
class ThreadLocal
{
public:
        typedef ThreadLocal<T>* pThreadLocal;  //指向模板的指针,应该用typedef定义一个别名来使用
private:
        pthread_key_t pkey;
private:
        static void destroy(void *x)
        {
                T *obj = static_cast <T*> (x);
                boost::checked_delete(obj);  //保证可以调用对象的析构函数
        }

public:
        ThreadLocal()  //这些操作都放进构造和析构,自动执行
        {
                pthread_key_create(&pkey, destroy);
        }
        ~ThreadLocal()
        {
                pthread_key_delete(pkey);
        }

        T& value()  //始终保证槽内只有一个T类型对象
        {
                T* pThreadData = static_cast <T*> (pthread_getspecific(pkey));
                if(pThreadData == NULL)
                {
                        T* newData = new T();
                        pthread_setspecific(pkey, newData);
                        pThreadData = newData;
                }
                return *pThreadData;
        }
};

class base
{
private:
        int count = 4;
public:
        void show()
        {
                count++;
                std::cout << count << std::endl;
        }
};

void* work(void* args)
{
        ThreadLocal<base>::pThreadLocal p = static_cast<ThreadLocal<base>::pThreadLocal>(args);  //p指向线程局部存储设施
        base &pb = p->value();  //如果槽内没有对象,则构造一个对象。始终保证槽内存在一个对象。
        pb.show();        //使用槽内的对象
}

int main()
{
        std::vector<pthread_t> vec(2);
        ThreadLocal<base>::pThreadLocal p = new ThreadLocal<base>;  //先构造一个ThreadLocal对象,此对象封装了线程局部存储设施。

        for(int i = 0; i < 2; ++i)
                pthread_create(&vec[i], NULL, work, static_cast<void*>(p));  //拉两个线程,并把上述对象传递过去
        for(int i = 0; i < 2; ++i)
                pthread_join(vec[i], NULL);

        delete p;
}

输出结果为 5和5 。可见两个线程未互相影响,base对象是存放在各自线程局部存储槽内的

__thread

陈硕在书中提了这个关键字,说是比pthread_key_t效率高

根据书中的说法:GCC内置的线程局部存储设施。只能用于修饰POD类型,不能修饰class类型(即不能修饰一个对象),因为无法自动调用构造函数和析构函数(有道理,毕竟是线程局部存储区域,c++的魔抓可能伸不到这里来)。__thread可以修饰全局变量,函数内的静态变量,但是不能用于修饰函数的局部变量(上面的pthread_key_t可以,用来存储一个栈上的流对象)或者class的普通成员变量。另外,__thread变量的初始化只能用编译期常量(new的话就别想了).

__thread string str; //error,不能调用对象的构造函数

__thread string *pStr = new string;  //error,初始化必须用编译期常量

__thread变量是每个线程有一份独立的实体,各个线程的变量值互不干扰。还有个用途:用来修饰“值可能会变,带有全局性,但是又不值得用全局锁保护”的变量。如果一个值,想在线程内被所有函数访问,但又不想被其他线程影响,可以试试__thread.

总之,用法不难,最重要的是要知道在什么时候用。这些都得靠经验之积累。

POD类型:

POD 类型(纯旧数据):C++ 中的此类非正式数据类型类别是指作为标量(参见基础类型部分)的类型或 POD 类。 POD 类没有不是 POD 的静态数据成员,没有用户定义的构造函数、用户定义的析构函数或用户定义的赋值运算符。 此外,POD 类无虚函数、基类、私有的或受保护的非静态数据成员。 POD 类型通常用于外部数据交换,例如与用 C 语言编写的模块(仅具有 POD 类型)进行的数据交换。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个使用 pthread 库的多线程程序,主要是创建一个线程并等待它的结束。下面是代码的详细解析: 1. `int main(int argc, char *argv[])`:程序的主函数。 2. `pthread_attr_t mtd_attr;`:定义线程属性对象 mtd_attr。 3. `pthread_attr_init(&amp;mtd_attr);`:初始化线程属性对象 mtd_attr。 4. `pthread_attr_setinheritsched(&amp;mtd_attr,PTHREAD_EXPLICIT_SCHED);`:设置线程属性对象 mtd_attr 的继承调度策略为 PTHREAD_EXPLICIT_SCHED。 5. `pthread_attr_setschedpolicy(&amp;mtd_attr,SCHED_OTHER);`:设置线程属性对象 mtd_attr 的调度策略为 SCHED_OTHER。 6. `struct sched_param send_param; send_param.__sched_priority = 60;`:定义并设置调度参数对象 send_param 的优先级为 60。 7. `pthread_attr_setschedparam(&amp;mtd_attr,&amp;send_param);`:设置线程属性对象 mtd_attr 的调度参数为 send_param。 8. `pthread_attr_setscope(&amp;mtd_attr,PTHREAD_SCOPE_SYSTEM);`:设置线程属性对象 mtd_attr 的作用域为 PTHREAD_SCOPE_SYSTEM。 9. `pthread_t mtd_thread;`:定义线程对象 mtd_thread。 10. `int mtd_task_id;`:定义线程 ID 变量 mtd_task_id。 11. `if((mtd_task_id=pthread_create((pthread_t *)(&amp;mtd_thread),&amp;mtd_attr,mtd_test,NULL))!=0)`:创建线程,并将其 ID 赋值给 mtd_task_id。其中,pthread_create() 函数的第一个参数是指向线程对象的指针,第二个参数是指向线程属性对象的指针,第三个参数是指向线程函数的指针,最后一个参数是线程函数的参数,这里设置为 NULL。 12. `printf(&quot;mtd_thread tid %d..\n&quot;,mtd_task_id);`:输出线程 ID。 13. `pthread_join(mtd_thread, NULL);`:等待线程结束,如果线程没有结束,主线程就会一直阻塞在这里。 14. `return 0;`:返回程序运行结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值