//本文参考博客
//http://www.cppblog.com/toMyself/archive/2010/09/22/127347.html
//开发环境 Visual Studio 2015
//boost16.8,下面是下载地址,有编译好的动态库,安装好后,在工程文件里引入头文件和库文件
//https://sourceforge.net/projects/boost/files/boost-binaries/1.68.0/
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/tss.hpp>
#include <boost/thread/once.hpp>
#include <boost/bind.hpp>
#include <iostream>
void hello()
{
std::cout << "Hello, I'm a thread!" << std::endl;
}
// 第一种方式:最简单方法
int main_01(int argc, char* argv[])
{
boost::thread t1(&hello);
t1.join();
//1. system是C标准库的, 是子进程执行shell解释command,可以在VisualStudio里执行
//2. 如果编译好可执行程序,可直接在cmd命令行里执行,注释掉system("pause");这一行,推荐用这种方式
system("pause");
return 0;
}
//第二种方式:复杂类型对象作为参数来创建线程
// 结构中也可以定义操作符
boost::mutex io_mutex;
// count是一个结构
struct count
{
//结构中提供了构造函数,因此要使用构造函数进行初始化
//关于构造函数参考
//https://msdn.microsoft.com/zh-cn/library/s16xw1a8.aspx
//下面的构造函数利用参数初始化成员变量,单个:就是访问成员变量的意思
//前面的id是参数,临时变量,后面的id是结构的成员变量
count(int id) : id(id) { }
void operator()()
{
for (int i = 0; i < 10; ++i)
{
boost::mutex::scoped_lock lock(io_mutex);
std::cout << id << ": " << i << std::endl;
}
}
int id;//默认为public
//如今的struct和class没啥两样,只是struct默认是public,class默认是private
};
int main_02(int argc, char* argv[])
{
count c1(1);
std::cout << c1.id << std::endl;
boost::thread thrd1(count(1));
boost::thread thrd2(count(2));
thrd1.join();
thrd2.join();
return 0;
}
//第三种方式:在类内部创建线程
//(1)类内部静态方法启动线程
class StaticHelloWorld
{
//在这里start()和hello()方法都必须是static方法
public:
static void hello()
{
std::cout << "Hello world, I'm a thread in HelloWorld Class!" << std::endl;
}
static void start()
{
boost::thread thrd(hello);
thrd.join();
}
};
//如果要执行这个,把main_31改为main
//因为只能有一个main函数
int main_31(int argc, char* argv[])
{
StaticHelloWorld::start();
return 0;
}
//(2)如果要求start()和hello()方法不能是静态方法则采用下面的方法创建线程:
class BindHelloWorld
{
public:
void hello()
{
std::cout << "Hello world, I'm a thread! use bind method" << std::endl;
}
void helloWithParamter(int i)
{
std::cout << "Hello world, I'm a thread! use bind method with parameter: "<< i << std::endl;
}
void start()
{
//bind用来向一个函数(或函数对象)绑定某些参数
//bind的返回值是一个函数对象
//参考博文
//https://www.cnblogs.com/blueoverflow/p/4740093.html
//https://www.boost.org/doc/libs/1_66_0/libs/bind/doc/html/bind.html
//https://www.jianshu.com/p/30e79d2a8f7d
//这个我不知道怎么定义,只能先用auto
auto f = boost::bind(&BindHelloWorld::hello, this);
//将这个函数对象传递给线程
boost::thread thrd(f);
thrd.join();
}
};
int main_32(int argc, char* argv[])
{
BindHelloWorld hello;
hello.start();
return 0;
}
//(3)在Singleton模式内部创建线程:
//第四种方法:用类内部函数在类外部创建线程
//这两种方式太复杂,懒得折腾了
//互斥体
//1. 一个互斥体一次只允许一个线程访问共享区。当一个线程想要访问共享区时,首先要做的就是锁住(lock)互斥体。
//2. Boost线程库支持两大类互斥体,包括简单互斥体(simple mutex)和递归互斥体(recursive mutex)。
// 有了递归互斥体,单个线程就可以对互斥体多次上锁,当然也必须解锁同样次数来保证其他线程可以对这个互斥体上锁。
//3. Boost线程库提供的互斥体类型:
// boost::mutex
// boost::try_mutex
// boost::timed_mutex
// boost::recursive_mutex
// boost::recursive_try_mutex
// boost::recursive_timed_mutex
// boost::shared_mutex
//
//4. mutex类采用Scope Lock模式实现互斥体的上锁和解锁。即构造函数对互斥体加锁,析构函数对互斥体解锁。
//5. 对应现有的几个mutex导入了scoped_lock,scoped_try_lock,scoped_timed_lock.
//6. scoped系列的特色就是析构时解锁,默认构造时加锁,这就很好的确定在某个作用域下某线程独占某段代码。
//条件变量
//1. 有的时候仅仅依靠锁住共享资源来使用它是不够的。有时候共享资源只有某些状态的时候才能够使用。
// 比方说,某个线程如果要从堆栈中读取数据,那么如果栈中没有数据就必须等待数据被压栈。这种情
// 况下的同步使用互斥体是不够的。另一种同步的方式--条件变量,就可以使用在这种情况下。
const int BUF_SIZE = 10;
const int ITERS = 100;
class buffer
{
public:
typedef boost::mutex::scoped_lock scoped_lock;
buffer() : p(0), c(0), full(0) {}
void put(int m)
{
scoped_lock lock(mutex);
if (full == BUF_SIZE)
{
{
boost::mutex::scoped_lock lock(io_mutex);
std::cout << "Buffer is full. Waiting..." << std::endl;
}
while (full == BUF_SIZE)
cond.wait(lock);
}
buf[p] = m;
p = (p + 1) % BUF_SIZE;
++full;
cond.notify_one();
}
int get()
{
scoped_lock lk(mutex);
if (full == 0)
{
{
boost::mutex::scoped_lock lock(io_mutex);
std::cout << "Buffer is empty. Waiting..." << std::endl;
}
while (full == 0)
cond.wait(lk);
}
int i = buf[c];
c = (c + 1) % BUF_SIZE;
--full;
cond.notify_one();
return i;
}
private:
boost::mutex mutex;
boost::condition cond;
unsigned int p, c, full;
int buf[BUF_SIZE];
};
buffer buf;
void writer()
{
for (int n = 0; n < ITERS; ++n)
{
{
boost::mutex::scoped_lock lock(io_mutex);
std::cout << "sending: " << n << std::endl;
}
buf.put(n);
}
}
void reader()
{
for (int x = 0; x < ITERS; ++x)
{
int n = buf.get();
{
boost::mutex::scoped_lock lock(io_mutex);
std::cout << "received: " << n << std::endl;
}
}
}
int main_04(int argc, char* argv[])
{
boost::thread thrd1(&reader);
boost::thread thrd2(&writer);
thrd1.join();
thrd2.join();
return 0;
}
//线程局部存储
//2018.12.11(不懂)
//函数的不可重入
//Boost线程库提供了智能指针boost::thread_specific_ptr来访问本地存储线程(thread local storage)。
boost::thread_specific_ptr<int> ptr;
struct count_local
{
count_local(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_05(int argc, char* argv[])
{
boost::thread thrd1(count(1));
boost::thread thrd2(count(2));
thrd1.join();
thrd2.join();
return 0;
}
//仅运行一次的例程
//1. 如何使得初始化工作(比如说构造函数)是线程安全的。
//2. “一次实现”(once routine)。“一次实现”在一个应用程序只能执行一次。
//3. Boost线程库提供了boost::call_once来支持“一次实现”,
// 并且定义了一个标志boost::once_flag,一个初始化这个标志的宏 BOOST_ONCE_INIT。
int i = 0;
boost::once_flag flag = BOOST_ONCE_INIT;
void init()
{
++i;
}
void thread()
{
boost::call_once(&init, flag);
}
int main(int argc, char* argv[])
{
boost::thread thrd1(&thread);
boost::thread thrd2(&thread);// 这个运行不到了
thrd1.join();
thrd2.join();
std::cout << i << std::endl;
return 0;
}