Boost线程学习

//本文参考博客
//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;
}

猜你喜欢

转载自blog.csdn.net/tjmuxuefeng/article/details/84952838