c++ posix线程库thread的封装和使用

POSIX的thread默认是joinable,需要手工调用pthread_join函数来回收,也可以调用pthread_detach将其变为detachable,此时不需要手工回收线程。
封装时有三个注意事项:

  1. Thread应该是不可拷贝的,所以继承noncopyable
  2. 其次,为了调用pthread_create创建线程,我们往里面注册的不能是一个成员函数,因为成员函数含有一个隐式参数(this),导致函数的指针类型并不是void *(*start_routine) (void *),所以我们采用了static函数。
  3. static函数无法访问某一对象的成员,所以我们在调用pthread_create时,将this指针作为回调函数的参数。

方式一

封装

下面采用继承的方式进行封装,子类只需公有继承Thread类并覆写其run方法。

  • 因为有虚函数run(),根据《Effctive C++》条款七,要把基类的析构函数声明为虚函数。
  • run为纯虚函数,子类必须覆写此方法,否则无法创建对象。
    (联想:将析构函数声明为纯虚函数会怎么样,见 https://www.cnblogs.com/chio/archive/2007/09/10/888260.html)
#ifndef _THREAD_H_
#define _THREAD_H_

#include "noncopyable.h"
#include 
#include 
#include 

#define CHECK(exp)\
    if(!exp) \
    { \
       fprintf(stderr,"file:%s,line:%d Exp:[" #exp "] not return 0\n",__FILE__,__LINE__);abort();\
    }

class Thread: public noncopyable{
public:
    Thread();
    virtual ~Thread();

    void join();
    virtual void run() = 0;
    void start();
    pthread_t getThreadId(){
        return tid_;
    }

private:
    static void* func(void* arg);

private:
    pthread_t tid_;
    bool isrunning_;
};
#endif // _THREAD_H_
#include "Thread.h"
#include 

Thread::Thread():tid_(0),isrunning_(false){

}

void Thread::start(){
    CHECK(!pthread_create(&tid_,NULL,Thread::func,(void*)this));
    isrunning_ = true;
}

void Thread::join(){
    assert(isrunning_ == true);
    CHECK(!pthread_join(tid_,NULL));
    isrunning_ = false;
}

void* Thread::func(void* arg){
    Thread* t = (Thread*)arg;
    t->run();

    return NULL;
}

Thread::~Thread(){
    if(isrunning_){
        CHECK(!pthread_detach(tid_));
    }
}
使用

还是利用封装Condition时的例子:
https://blog.csdn.net/littleflypig/article/details/89210990
这次把线程换成我们自己的。

#include 
#include "MutexLock.h"
#include 
#include 
#include 
#include 
#include "Condition.h"
#include "Thread.h"

using namespace std;

const int num = 10;

int count=0;
MutexLock mutex;
Condition cond(mutex);

pid_t gettid(){
    return syscall(__NR_gettid);
}
class ConsumerThread : public Thread{
public:
    void run(){
        pid_t tid = gettid();
        for(int i=0;i<num;++i){

            MutexLockGuard lock(mutex);
            while(count == 0){
                cond.wait();
            }
            cout<<"consume "<<tid<<": "<<count<<endl;
            count--;
        }
    }
};

class ProducerThread : public Thread{
public:
    void run(){
        pid_t tid = gettid();

        for(int i=0;i<2*num;++i){
            MutexLockGuard lock(mutex);
            count++;
            cout<<"produce "<<tid<<": "<<count<<endl;
            cond.notify();
        }
    }
};

int main()
{
    ConsumerThread c1,c2;
    ProducerThread p;

    c1.start();
    c2.start();
    p.start();

    c1.join();
    c2.join();
    p.join();

    cout<<count<<endl;
}

有几个点需要注意:

  1. 继承Thread类时要使用public继承,这样才能在main函数(用户代码)中调用基类部分的start,join等方法。
  2. Thread派生类可以不写析构,由编译器合成默认的。

参考:http://www.cnblogs.com/inevermore/p/4008572.html

方式二

利用std的function模板,需要注意的点是setCallback的参数必须要声明为const类型的引用,否则编译会报错。

#ifndef _THREAD2_H_
#define _THREAD2_H_

#include "noncopyable.h"
#include 
#include 
#include 
#include 

#define CHECK(exp)\
    if(!exp) \
    { \
       fprintf(stderr,"file:%s,line:%d Exp:[" #exp "] not return 0\n",__FILE__,__LINE__);abort();\
    }

typedef std::function<void ()> funcCallback;

class Thread2: public noncopyable{
public:
    Thread2();
    ~Thread2();

    void join();
    void start();
    pthread_t getThreadId(){
        return tid_;
    }
    void setCallback(const funcCallback& c){
        callback_ = c;
    }

private:
    static void* func(void* arg);

private:
    pthread_t tid_;
    bool isrunning_;
    funcCallback callback_;
};
#endif // _THREAD_H_
#include "Thread2.h"
#include 

Thread2::Thread2():tid_(0),isrunning_(false){

}

void Thread2::start(){
    CHECK(!pthread_create(&tid_,NULL,Thread2::func,(void*)this));
    isrunning_ = true;
}

void Thread2::join(){
    assert(isrunning_ == true);
    CHECK(!pthread_join(tid_,NULL));
    isrunning_ = false;
}

void* Thread2::func(void* arg){
    Thread2* t = (Thread2*)arg;
    t->callback_();

    return NULL;
}

Thread2::~Thread2(){
    if(isrunning_){
        CHECK(!pthread_detach(tid_));
    }
}

使用起来感觉比较方便,不用继承了

include <iostream>
#include "MutexLock.h"
#include 
#include 
#include 
#include 
#include "Condition.h"
#include "Thread2.h"

using namespace std;

const int num = 10;

int count=0;
MutexLock mutex;
Condition cond(mutex);

pid_t gettid(){
    return syscall(__NR_gettid);
}

void consume(){
    pid_t tid = gettid();
    for(int i=0;i<num;++i){

        MutexLockGuard lock(mutex);
        while(count == 0){
            cond.wait();
        }
        cout<<"consume "<<tid<<": "<<count<<endl;
        count--;
    }
}

void produce(){
    pid_t tid = gettid();

    for(int i=0;i<2*num;++i){
        MutexLockGuard lock(mutex);
        count++;
        cout<<"produce "<<tid<<": "<<count<<endl;
        cond.notify();
    }
}


int main()
{
    Thread2 c1,c2,p;
    c1.setCallback(consume);
    c2.setCallback(consume);
    p.setCallback(produce);

    c1.start();
    c2.start();
    p.start();

    c1.join();
    c2.join();
    p.join();

    cout<<count<<endl;
}

而且想要传参数给线程任务函数也是可以的,用bind将参数绑定即可,如下:

void consume(int arg){
    pid_t tid = gettid();
    for(int i=0;i<num;++i){

        MutexLockGuard lock(mutex);
        while(count == 0){
            cond.wait();
        }
        cout<<"consume "<<tid<<": "<<count<<endl;
        count--;
    }
}

int main()
{
    Thread2 c1,c2,p;
    c1.setCallback(bind(consume,1));  //bind参数
    c2.setCallback(bind(consume,2));
    p.setCallback(produce);

    c1.start();
    c2.start();
    p.start();

    c1.join();
    c2.join();
    p.join();

    cout<<count<<endl;
}

你可能感兴趣的:(c++,posix库封装)