C++并发实战1:thread object

boost::thread的使用

首先确定安装了boost,ubuntu采用:sudo apt-get install libboost-dev

再安装:sudo apt-get install libboost-thread

1     编写如下文件:

#include<boost/thread.hpp>
#include<unistd.h>
#include<sys/syscall.h>
#include<iostream>
using namespace std;
void show(){
    cout<<"hello wolrd "<<syscall(SYS_gettid)<<endl;
}
int main(){
    boost::thread t(show);//这里还可以t(&show)也能成功和pthread_create一样
    cout<<"main pid "<<syscall(SYS_gettid)<<" "<<t.get_id()<<endl;
    //t.detach();
    if(!t.joinable())
        cout<<"thread unjoinable"<<endl;
    else{
        cout<<"thread joinable"<<endl;
        t.join();
    }
    return 0;
}

注意编译的时候一定要带上 -lboost_thread否则会报错: undefined reference to `boost::thread::join()'等,假设上面程序文件为test.cpp则编译为:g++ -o test test.cpp -lboost_thread


2     boost::thread可以接收一个函数对象作为参数 ,函数对象会被拷贝进线程空间,那么这里就要注意一个问题:拷贝语义,若必要请采用深拷贝

#include<boost/thread.hpp>
#include<iostream>
using namespace std;
using namespace boost;
class test{
    public:
        void operator()() const{
            cout<<"operator() "<<*data<<endl;
        }
        test(int a=10){
            cout<<"constructor"<<endl;
            data=new int(a);
        }
        int get() const{
            return *data;
        }
        test(const test& one){
            cout<<"copy constructor"<<endl;
            //data=new int(one.get());//深拷贝,否则段错误
        }
    private:
        int* data;
};
int main(){
    test one;
    thread myThread(one);//函数对象被拷贝进线程空间
    myThread.join();
    return 0;
}

程序输出:

constructor
copy constructor
copy constructor
copy constructor
copy constructor                    //为什么这么多拷贝????
段错误 (核心已转储)             //这里采用深拷贝可以消除段错误


3      可以向thread传递临时函数对象

#include<boost/thread.hpp>
#include<iostream>
using namespace std;
using namespace boost;
class test{
    public:
        void operator()() const{
            cout<<"operator() "<<*data<<endl;
        }
        test(int a=10){
            cout<<"constructor"<<endl;
            data=new int(a);
        }
        int get() const{
            return *data;
        }
        test(const test& one){
            cout<<"copy constructor"<<endl;
            data=new int(one.get());//深拷贝,否则段错误
        }
    private:
        int* data;
};
int main(){
    //thread mythread(test());//错误,会被误以为一个无参数的函数指针并返回一个test对象,从而返回一个thread对象而不是启动线程
    thread myThread((test()));//多余的括号用于防止被解释为一个函数
    //thread myThread{test()};//书上这种用法,编译通不过
    //也可以用函数对象test one(11);thread myThread(one);
    myThread.join();
    return 0;
}

程序输出:
constructor
copy constructor
copy constructor
copy constructor               //少了一次拷贝,我已经无法解释了,求高人指教~
operator() 10

4         thread结合boost::bind使用
#include<iostream>
#include<boost/thread.hpp>
#include<boost/bind.hpp>
using namespace std;
void show(){
    cout<<"show()"<<endl;
}
int main(){
    boost::thread t(boost::bind(show));
    t.join();
    return 0;
}

程序输出:

show()


5          thread还可以结合lambda表达式使用(lambda表达式不熟悉~待完善)


线程可能先于join完成,此时仍joinable

#include<iostream>
#include<boost/thread/thread.hpp>
#include<unistd.h>
using namespace std;
using namespace boost;
void show(){
    cout<<"thread show()"<<endl;
}
int main(){
    thread t(show);
    sleep(1);
    if(t.joinable()){
        cout<<"joinable"<<endl;
        t.join();
    }
    else{
        cout<<"unjoinable"<<endl;
    }
    return 0;
}

程序输出:

thread show()
joinable


6          当detach线程后,线程生命周期可能长于thread对象

#include<iostream>
#include<boost/thread/thread.hpp>
#include<unistd.h>
using namespace std;
using namespace boost;
void show(){
    sleep(1);
    cout<<"thread show"<<endl;
}
int main(){
    {
        thread t(show);
        t.detach();
    }
    sleep(2);
    return 0;
}

程序输出:

thread show


7          当一个thread对象销毁前,必须显示的指定是join还是detach线程(必须保证join和detach的正确即使在异常抛出中。在thread对象销毁前作这个是join还是detach),否则一旦线程对象销毁后,thread析构函数对调用terminate()结束线程。如下:

#include<iostream>
#include<unistd.h>
#include<boost/thread.hpp>
using namespace std;
void fun(){
    for(int i=0;i<5;i++){
        cout<<"thread::fun()"<<endl;
        sleep(1);
    }
}
int main(){
    {
        boost::thread t(fun);
    }
    cout<<"main exit"<<endl;
    sleep(2);
    return 0;
}
程序输出:

main exit
thread::fun()
thread::fun()                //子线程并没有输出5个thread::fun()说明被提前terminate了


8          如果不等待线程完成,一定要确保线程存取的对象是有效的。比如:当线程函数持有一个局部变量的引用或指针时,但是这个局部变量缺被销毁了。

#include<iostream>
#include<boost/thread.hpp>
using namespace std;
void do_something(int& i){
    i++;
    cout<<i<<" ";
}
class func{
    public:
        func(int& i):i_(i){}
        void operator()(){
            for(int j=0;j<100;j++)
                do_something(i_);
        }
    public:
        int &i_;
};
void oops(){
    int local=0;
    func my_func(local);
    boost::thread my_thread(my_func);
    my_thread.detach();//分离线程
    cout<<"oops() "<<local<<endl;//局部对象将会被销毁,do_something输出会出错
}
int main(){
    oops();
    return 0;
}

程序输出:

oops() 0            //局部对象已经被销毁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29   //预想是输出1-100的数。


9      采用c++11重写演示上面程序:

#include<iostream>
//#include<boost/thread.hpp>
#include<thread>
using namespace std;
void do_something(int& i){
    i++;
    cout<<i<<" ";
}
class func{
    public:
        func(int& i):i_(i){}
        void operator()(){
            for(int j=0;j<100;j++)
                do_something(i_);
        }
    public:
        int &i_;
};
void oops(){
    int local=0;
    func my_func(local);
    thread my_thread(my_func);
    my_thread.detach();
    cout<<"oops() "<<local<<endl;
}
int main(){
    oops();
    return 0;
}

假设文件保存为:test.cpp编译时: g++ -o test test.cpp -std=c++0x -lpthread,执行./test

oops() 01 2 3 4 5 6 7 8 9 10

   说明:子线程my_thread被分离后,oops()退出使局部对象my_func析构了(local也销毁了),此时子线程调用do_something()访问一个已经销毁的对象,从而错误。解决的办法是:子线程将数据拷贝到自己空间,从而替代共享数据的访问。这个问题类似于对象生命周期的管理,出现了析构竞态,也可以采用boost::shared_ptr管理对象的生命周期。

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值