スレッドパッケージ

4793 ワード

Linuxでは元のAPIが使いにくいため,使いやすいようにスレッド関連APIをカプセル化してみる.
「Linuxマルチスレッドサービス端プログラミング」を見て、陳碩はオブジェクトに基づいてカプセル化され、boost::bindを使用して関数オブジェクトを作成し、関数オブジェクトをスレッドとして実行する関数である.今回はオブジェクト向けのカプセル化を試み,スレッドベースクラスを作成し,サブクラスがこのベースクラスを継承し,スレッド実行の主体関数を実現すればよい.ベースクラスは次のとおりです.
class BaseThread
{
public:
    BaseThread(const std::string& name);
    virtual ~BaseThread();
     void Run();
    void Join();
    static void* ThreadProxy(void* argument);
protected:
    virtual void DoTask() = 0;

private:
    void Initilization();
    bool initilized_;
    bool started_;
    bool joined_;
    pthread_t pthreadId_;
    pid_t tid_;
    std::string name_;

};

変数には、スレッドの名前、id(整数)、スレッド識別子、起動するかどうか、初期化するかどうかなどが含まれます.純虚関数DoTaskはスレッド実行の主体関数であり,この関数をサブクラスで実現すればよい.
静的関数ThreadProxyは、スレッド作成後に実行されるエントリである.スレッドがAPIを作成するため
int pthread_create(pthread_t *tidp,const pthread_attr_t *attr,
(void*)(*start_rtn)(void*),void *arg);
start_rtnはスレッド作成後に実行される関数です.静的関数にはthisポインタがあるため、スレッドのエントリ関数として使用できません.解決策1、グローバル関数を使う.これにより、クラスのprivateおよびprotectedメンバーにアクセスすることが困難になります.2、友元関数.3、静的関数.静的関数の方法を用いた.
実現を見てみましょう
BaseThread::BaseThread(const std::string& name)
    :initilized_(false),
    started_(false),
    joined_(false),
    pthreadId_(0),
    tid_(pid_t(0)),
    name_(name)
{}
BaseThread::~BaseThread()
{
    if(initilized_ && started_ && !joined_)
        pthread_detach(pthreadId_);
}
void BaseThread::Run()
{
    assert(!started_);
    started_=true;
    //create the thread
    pthread_create(&pthreadId_,
        NULL,
        BaseThread::ThreadProxy,
        this);

}
void BaseThread::Join()
{
    assert(started_);
    assert(!joined_);
    pthread_join(pthreadId_, NULL);
}

/*staitc function used to call the real Task */
void* BaseThread::ThreadProxy(void* argument) 
{
    BaseThread* thread=static_cast<BaseThread*>(argument);
    thread->Initilization();
    thread->started_=true;
    thread->DoTask();
    return static_cast<void*> (0);

}

void BaseThread::Initilization() //must be called by the new thread
{
    tid_=static_cast<pid_t>(::syscall(SYS_gettid));
    initilized_=true;
}

実装時には、Runでスレッドを作成し、スレッド関数を実行します.ここでthisポインタをパラメータとするのは、ThreadEntryでBaseThreadクラスの他のメンバーを呼び出すのを容易にするためです.
コンストラクション関数では、クラスコンストラクション時にスレッドが実行され、joinがない場合に分離します.
このような基本的なパッケージは完成しました.スレッドの同期についてはmuduoネットワークライブラリを参照してカプセル化した.
以下にいくつかのテストを書きます:すべて生産者消費者モデルについてで、ここ1、生産者と消費者が独立したクラスとして存在することを参考にして、main関数の中で生産者クラスと消費者クラスをスケジューリングすることができます.このように実現するには,生産者と消費者の同期を要求すると,グローバル同期変数が必要となる.インプリメンテーションリファレンス:https://github.com/KangRoger/ThreadLib/blob/master/test/ConsumerAndProductor/ConsumerAndProductor.cpp
2、生産者、消費者はメンバー変数として存在し、クラスConsumer AndProductorに含まれる.この場合、同期変数はすべて生産者/消費者のプライベート変数として使用され、彼らが使用する反発量と条件変数は同じであり、ポインタまたは参照を使用することができる.インプリメンテーションリファレンス:https://github.com/KangRoger/ThreadLib/blob/master/test/ConsumerAndProductor/ConsumerAndProductor2.cpp
スレッドライフサイクル管理には問題があり、その後改善されます.