boost::thread_specific_ptr
今天看代码发现用到了boost库的thread_specific_ptr,就在网上搜了下
线程私有变量(Thread Local Storage)之于线程相当于静态变量之于进程,与进程变量相比是每个线程都有一份, 也就是所谓的“私有”。也可以把线程私有变量理解为key-value对,其中key是线程ID。它的主要作用是在多线程编程中避免锁竞争的开销。其多种实现及原理可见:https://spockwangs.github.io/blog/2017/12/01/thread-local-storage/ 本文主要看Boost的TLS实现
大多数函数都不是可重入的。这也就是说在某一个线程已经调用了一个函数时,如果你再调用同一个函数,那么这样是不安全的。一个不可重入的函数通过连续的调用来保存静态变量或者是返回一个指向静态数据的指针。
举例来说,std::strtok就是不可重入的,因为它使用静态变量来保存要被分割成符号的字符串。有两种方法可以让不可重用的函数变成可重用的函数。第一种方法就是改变接口,用指针或引用代替原先使用静态数据的地方。比方说,POSIX定义了strok_r,std::strtok中的一个可重入的变量,它用一个额外的char**参数来代替静态数据。这种方法很简单,而且提供了可能的最佳效果。但是这样必须改变公共接口,也就意味着必须改代码。另一种方法不用改变公有接口,而是用本地存储线程(thread local storage)来代替静态数据(有时也被成为特殊线程存储,thread-specific storage)。
Boost线程库提供了智能指针boost::thread_specific_ptr来访问本地存储线程。每一个线程第一次使用这个智能指针的实例时,它的初值是NULL,所以必须要先检查这个它的只是否为空,并且为它赋值。Boost线程库保证本地存储线程中保存的数据会在线程结束后被清除。
下方是一个使用boost::thread_specific_ptr的简单例子。其中创建了两个线程来初始化本地存储线程,并有10次循环,每一次都会增加智能指针指向的值,并将其输出到std::cout上(由于std::cout是一个共享资源,所以通过互斥体进行同步)。main线程等待这两个线程结束后就退出。从这个例子输出可以明白的看出每个线程都处理属于自己的数据实例,尽管它们都是使用同一个boost::thread_specific_ptr。
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/tss.hpp>
#include <iostream>
boost::mutex io_mutex;
boost::thread_specific_ptr<int> ptr;
struct count
{
count(int id) : id(id) { }
void operator()()
{
if (ptr.get() == 0)
ptr.reset(new int(0));
for (int i = 0; i < 10; ++i)
{
(*ptr)++;
boost::mutex::scoped_lock
lock(io_mutex);
std::cout << id << ": "
<< *ptr << std::endl;
}
}
int id;
};
int main(int argc, char* argv[])
{
boost::thread thrd1(count(1));
boost::thread thrd2(count(2));
thrd1.join();
thrd2.join();
return 0;
}
boost::split
拆分字符串的,直接上例子
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <string>
#include <vector>
using namespace boost::algorithm;
using namespace std;
int main(){
string str("miss,you.just.call_to,say,I~love~you");
vector<string> strVec;
split(strVec, str, is_any_of(",."));
vector<string>::iterator it = strVec.begin();
for (; it!=strVec.end(); it++){
cout << *it << endl;
}
return 0;
}
运行的结果就是都拆出来了 miss you just call to say I~love~you, 注意分隔符是 , . 没有用~, 所有后面的I~love~you没有拆
头文件统一的话就用的#include<boost/algorithm/string.hpp> 9, 10行就是split的使用方式
boost::mutex::scoped_lock
区域锁boost::mutex::scoped_lock顾名思义就是在作用域内有效,当离开作用域自动释放锁,传递参数是锁
区域锁就是把锁封装到一个对象里面。锁的初始化放到构造函数,锁的释放放到析构函数。这样当锁离开作用域时,
析构函数会自动释放锁。即使运行时抛出异常,由于析构函数仍然会自动运行,所以锁仍然能自动释放。一个典型的区域锁
void CSettingCenter::ClearPlatformServiceInfoCache()
{
boost::mutex::scoped_lock lock(m_mutexAccessServiceManager);
m_mapAccessServiceManager.clear();
}
应用于有大量的return返回的代码,避免出现死锁的问题
boost::function 与 boost::bind
boost::bind 是std::bindlist 和 std::bind2nd的结合体。它提供一个任意的函数对象(仿函数)、函数、函数指针、成员函数指针。 它可以绑定任意的参数。bind 没有对函数对象有任何的要求。
void print(int array[], int size)
{
for (int i = 0; i < size; i++) {
printf("%d\n", array[i]);
}
}
int main(int argc, const char *argv[])
{
int array[]= {1,2,1,34,5,5,56,9,6,10};
int len = sizeof(array)/sizeof(array[0]);
// 绑定普通函数
boost::bind(print, _1,_2)(array, len);
// 与function结合
boost::function<void(int [], int)> fn = boost::bind(print, _1,_2);
fn(array, len); return 0;
}
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <stdio.h>
#include <string>
#include <map>
class SimpleLineReader {
public:
SimpleLineReader (const string& filename)
{
fp_ = fopen(filename.c_str(), "r");
}
~SimpleLineReader (){
if (fp_) {
fclose(fp_);
}
}
typedef boost::function<bool (const std::string& line)> Callback; // here
bool ProcessLines(Callback fn)
{
if (!fp_)
{
return false;
}
char *line = NULL;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, fp_)) != -1) {
string str(line, read);
fn(line);
}
free(line);
return true;
}
private:
FILE* fp_;
};
class CityLoader {
public:
CityLoader (){}
int init(const std::string& filename)
{
SimpleLineReader reader(filename);
reader.ProcessLines(boost::bind(&CityLoader::ProcessLine, this, _1)); // here
printf("readline\t%d\n", city_map_.size());
}
~CityLoader ()
{
}
private:
bool ProcessLine(const std::string& line)
{
static int cnt = 0;
if (line.empty())
{
return true;
}
city_map_.insert(make_pair(++cnt, line));
return true;
}
std::map<int, std::string> city_map_;
};
void test_simple_line_reader()
{
CityLoader city_loader;
city_loader.init("data/city.txt");
}
int main()
{
test_simple_line_reader();
}
注意 function<void(void)>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>
typedef boost::function<void(void)>Func;
void print_string(const std::string s)
{
std::cout<<"s:"<<s<<std::endl;
}
int main()
{
Func f(boost::bind(print_string,"hello bind"));
f();
return 0;
}