日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

muduo源码分析3——TSD

發布時間:2024/5/14 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 muduo源码分析3——TSD 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1 什么是tsd

因為全局變量在所有線程中是共享的,如何才能擁有只在單個線程中共享的全局數據呢?這就需要tsd了。
可能會有疑問,這玩意到底有啥用,在線程中定義一個變量,其內部函數不也能使用嗎?但是其不是全局的,需要傳入到函數。

  • 線程私有數據采用了一種被稱為一鍵多值的技術,即一個鍵對應多個數值,當需要使用該值時,通過key獲取實際數據。
  • key一旦被創建,所有線程都可以訪問它,但各線程可根據自己的需要往key中填入不同的值,這就相當于提供了一個同名而不同值的全局變量,一鍵多值。
  • 一個線程中可以有多個key
  • 2 相關函數

    int pthread_key_create(pthread_key_t *key, void (*destructor) (void *)) 創建成功返回0,失敗返回errno

    destructor定義后,當線程結束時,會調用該函數來完成key指向內存清理

    int pthread_key_delete(pthread_key_t key); 成功返回0,失敗返回errno man手冊解釋如下,cleanup操作可以在pthread_key_delete調用前后,pthread_key_delete只負責刪除key指針,但是cleanup是destructor函數完成It is the responsibility of the application to free any application storage or perform any cleanup actions for data structures related to the deleted key or associated thread-specific data in any threads; this cleanup can be done either before or after pthread_key_delete() is called. int pthread_setspecific(pthread_key_t key, const void *value); 成功返回0,失敗返回errno 設置key指向的值 void * pthread_getspecific(pthread_key_t key); 成功返回0,失敗返回errno 返回指向的值的指針

    3 測試代碼

    下面寫了測試代碼

  • 兩個線程中,都使用了一個key,但是指向的是不同的值
  • fun()中使用pthread_getspecific獲取線程內部全局變量,省去傳參
  • #include <iostream>using namespace std; pthread_t tid1,tid2; pthread_key_t key; void deleter(void* key) {cout<<"deleter"<<key<<endl;free(key); //清理內存} void* thread_fun2(void*) {int *myValue = new int(2);int priValue = 11;pthread_setspecific(key,(void*)myValue);printf("thread2:%lu return %d\n", pthread_self(), *(int*)pthread_getspecific(key));printf("priValue is %d\n",priValue);} void fun() {cout<<"fun"<<*(int*)pthread_getspecific(key)<<endl;//myValue就是線程內部的全局變量 } void* thread_fun1(void*) {int priValue = 10;int *myVec = new int[10];cout<<"myVec"<<myVec<<endl;myVec[0] = 22;myVec[1] = 33;pthread_setspecific(key,(void*)myVec);pthread_create(&tid2,NULL,thread_fun2,NULL);printf("thread1:%lu return %d\n", pthread_self(), *(int*)pthread_getspecific(key));fun(); }int main() {pthread_key_create(&key, deleter); //創建key和刪除器cout<<"go"<<endl;pthread_create(&tid1,NULL,thread_fun1,NULL);pthread_join(tid1,NULL);pthread_join(tid2,NULL);pthread_key_delete(key); //在刪除key之前,要先清理線程cout<<"end"<<endl;return 0;} xili271948@er04180p:/data/lxz/muduo_test/pthread_key$ ./copymain go myVec0x7fd4e0000b20 thread1:140552344831744 return 22 22 deleter0x7fd4e0000b20 thread2:140552267888384 return 2 priValue is 11 deleter0x7fd4d8000b20 end

    4 muduo中的tsd

    4.1 muduo的tsd怎么用

    value()函數做了如下工作

  • 先pthread_getspecific,如果key沒有設置過值,則new T,再set
  • 如果key設置了值,則返回get的值
  • 注意其返回的是引用,所以可以直接對key指向的值進行更改
  • 每次只需要調用value函數即可,完成get,set等操作。

    // Use of this source code is governed by a BSD-style license // that can be found in the License file. // // Author: Shuo Chen (chenshuo at chenshuo dot com)#ifndef MUDUO_BASE_THREADLOCAL_H #define MUDUO_BASE_THREADLOCAL_H#include "muduo/base/Mutex.h" #include "muduo/base/noncopyable.h"#include <pthread.h>namespace muduo {template<typename T> class ThreadLocal : noncopyable {public:ThreadLocal(){MCHECK(pthread_key_create(&pkey_, &ThreadLocal::destructor));}~ThreadLocal(){MCHECK(pthread_key_delete(pkey_));}T& value(){T* perThreadValue = static_cast<T*>(pthread_getspecific(pkey_));if (!perThreadValue){T* newObj = new T();MCHECK(pthread_setspecific(pkey_, newObj));perThreadValue = newObj;}return *perThreadValue;}private:static void destructor(void *x){T* obj = static_cast<T*>(x);typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];T_must_be_complete_type dummy; (void) dummy;delete obj;}private:pthread_key_t pkey_; };} // namespace muduo#endif // MUDUO_BASE_THREADLOCAL_H

    4.2 muduo 測試代碼

    #include "muduo/base/ThreadLocal.h" #include "muduo/base/CurrentThread.h" #include "muduo/base/Thread.h"#include <stdio.h>class Test : muduo::noncopyable {public:Test(){printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this);}~Test(){printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str());}const muduo::string& name() const { return name_; }void setName(const muduo::string& n) { name_ = n; }private:muduo::string name_; };muduo::ThreadLocal<Test> testObj1; muduo::ThreadLocal<Test> testObj2;void print() {printf("tid=%d, obj1 %p name=%s\n",muduo::CurrentThread::tid(),&testObj1.value(),testObj1.value().name().c_str());printf("tid=%d, obj2 %p name=%s\n",muduo::CurrentThread::tid(),&testObj2.value(),testObj2.value().name().c_str()); }void threadFunc() {print();testObj1.value().setName("changed 1");testObj2.value().setName("changed 42");print(); }int main() {testObj1.value().setName("main one");print();muduo::Thread t1(threadFunc);t1.start();t1.join();testObj2.value().setName("main two");print();pthread_exit(0); } lxz@lxz-VirtualBox:~/liuxz/testmuduo/threadlocal/build$ ./thread_local tid=2665, constructing 0x55b96a73ee70 tid=2665, obj1 0x55b96a73ee70 name=main one tid=2665, constructing 0x55b96a73f2b0 tid=2665, obj2 0x55b96a73f2b0 name= tid=2666, constructing 0x7fd93c000b20 tid=2666, obj1 0x7fd93c000b20 name= tid=2666, constructing 0x7fd93c000b50 tid=2666, obj2 0x7fd93c000b50 name= tid=2666, obj1 0x7fd93c000b20 name=changed 1 tid=2666, obj2 0x7fd93c000b50 name=changed 42 tid=2666, destructing 0x7fd93c000b20 changed 1 tid=2666, destructing 0x7fd93c000b50 changed 42 tid=2665, obj1 0x55b96a73ee70 name=main one tid=2665, obj2 0x55b96a73f2b0 name=main two tid=2665, destructing 0x55b96a73ee70 main one tid=2665, destructing 0x55b96a73f2b0 main two

    總結

    以上是生活随笔為你收集整理的muduo源码分析3——TSD的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。