IPerf开源代码中Thread类分析

一 点睛

Tread类封装了POSIX标准中的多线程机制,提供了一种简单易用的线程模型。Thread类是IPerf实现中比较重要的类,是IPerf实现多线程并行操作的核心。

二 Thread类的定义

1 类定义于lib/Thread.hpp中,其实现位于lib/Thread.cpp中。

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

    // 启动和停止一个线程
    void Start( void );
    void Stop( void );

    // run是线程的主循环
    // 通常它被Start()调用, 但也可能被单线程应用程序调用.
    virtual void Run( void ) = 0;

    // 等待子线程结束
    void Join( void );
    // 等待所有线程结束
    static void Joinall( void );

    // 通过该函数说明是否在线程结束后释放该线程的变量
    void DeleteSelfAfterRun( void ) {
        mDeleteSelf = true;
    }

    // 将线程设置后一个后台线程, 这样 joinall 就不会等该线程了
    void SetDaemon( void );

    // returns the number of user (i.e. not daemon) threads
    static int NumUserThreads( void ) {
        return sNum;
    }

    static nthread_t GetID( void );

    static bool EqualID( nthread_t inLeft, nthread_t inRight );

    static nthread_t ZeroID( void );

protected:
    // 记录本线程的线程ID
    nthread_t mTID;
    bool mDeleteSelf;

#if defined( HAVE_WIN32_THREAD )
    HANDLE mHandle;
#endif

    // 它为一个静态变量,为所有Thread实例所共有。该变量记录所生成线程的总数。Thread对象的Joinall方法通过该变量判断所有的Thread实例是否执行结束
    static int sNum;
    // 用来同步对sNum操作的条件变量
    static Condition sNum_cond;

private:
    static void*        Run_Wrapper( void* paramPtr );

}; // end class Thread

三 主要函数说明

1 Start

void Thread::Start( void ) {
    if ( EqualID( mTID, ZeroID() ) ) {

        // 记录一个新线程的产生
        sNum_cond.Lock();
        sNum++;
        sNum_cond.Unlock();

        Thread* ptr = this;

        // 产生一个新线程,新线程执行Run_Wrapper函数,并把ptr指针作为参数
        int err = pthread_create( &mTID, NULL, Run_Wrapper, ptr );
        //原线程在判断返回值是否成功后退出Start函数
        FAIL( err != 0, "pthread_create" );
    }
} // end Start

2 Stop

void Thread::Stop( void ) {
    if ( ! EqualID( mTID, ZeroID() ) ) {
        // 通过sNum记录一个线程执行结束
        sNum_cond.Lock();
        sNum--;
        // 激活wait在sNum_cond的线程(某个主线程会调用Joinall方法,等待全部线程的结束,在Jainall方法中通过sNum_cond.Wait()在sNum_cond条件变量上等待)
        sNum_cond.Signal();
        sNum_cond.Unlock();
        nthread_t oldTID = mTID;
        mTID = ZeroID();

        // exit thread

        // 如果结束线程是自身,则调用pthread_exit函数结束
        // 否则调用pthread_cancel
        if ( EqualID( pthread_self(), oldTID ) ) {
            pthread_exit( NULL );
        } else {
            // Cray J90 doesn't have pthread_cancel; Iperf works okay without
            pthread_cancel( oldTID );
        }
    }
} // end Stop

3 Run_Wrapper

// 该函数是一个外部函数(wrapper),主要功能是调用本实例的Run方法
//  由于它是一个静态方法,是为所有Thread实例所共有的,一次无法使用this指针
// 通过参数paramPtr指明具体的Thread实例
Thread::Run_Wrapper( void* paramPtr ) {
    assert( paramPtr != NULL );

    Thread* objectPtr = (Thread*) paramPtr;

    // run (pure virtual function)
    objectPtr->Run();
    // detach Thread. If someone already joined it will not do anything
    // If noone has then it will free resources upon return from this
    // function (Run_Wrapper)
    // 线程变成可分离线程,线程运行结束后释放线程资源
    pthread_detach(objectPtr->mTID);

    // set TID to zero, then delete it
    // the zero TID causes Stop() in the destructor not to do anything
    objectPtr->mTID = ZeroID();

    // 释放线程
    if ( objectPtr->mDeleteSelf ) {
        DELETE_PTR( objectPtr );
    }

    // decrement thread count and send condition signal
    // do this after the object is destroyed, otherwise NT complains
    // Joinall通过监视sNum数量等待所有线程运行结束
    sNum_cond.Lock();
    sNum--;
    // 通知在Joinall中等待的线程
    sNum_cond.Signal();
    sNum_cond.Unlock();

    return NULL;
} // end run_wrapper

4 Run

该方法是一个纯虚函数,因此Thread是一个抽象基类,主要作用是为其派生类提供统一的对外接口。在Thread的派生类中,像iPerf中的Server、Client、Speader、Audience、Listener等类都会为Run提供特定的实现,以完成不同功能,这是对面向对象设计多态特性的运用。Thread函数通过Run方法提供一个通用的线程接口。

Thread的各派生类完成的功能不同,但他们都是Thread的实例,都有一些相同的工作要做,如初始化和清理等。在Run_Wrapper中实现这些作为Thread实例所应有的相同功能,在Run函数中实现派生类各自不同的功能,是比较合理的设计。

Pthread_create函数调用Run_Wrapper函数,因此Run_Wrapper必须是一个静态成员,无法使用this指针区分运行Run_Wrapper函数的具体实例,也就无法利用多态特性。而这个问题可以通过把this指针作为Run_Wrapper函数的参数,并在Run_Wrapper中显示调用具有多态特性的Run函数来解决。

这种使用wrapper函数技术为我们提供了一种将C++面向对象编程和传统的Linux系统调用相结合的思路。

5 Joinall和SetDaemon

void Thread::Joinall( void ) {
    sNum_cond.Lock();
    // 通过sNum监视运行的线程数。线程开始前sNum加一,线程结束后,sNum减一。
    // 通过条件变量sNum_cond的wait方法等待sNum的值改变
    while ( sNum > 0 ) {
        sNum_cond.Wait();
    }
    sNum_cond.Unlock();
} // end Joinall
// 使调用线程不再受主线程Joinall的约束,只是简单把sNum减一就可以了。
void Thread::SetDaemon( void ) {
    sNum_cond.Lock();
    sNum--;
    sNum_cond.Signal();
    sNum_cond.Unlock();
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值