打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Iperf 源代码分析(二)
转自:http://blog.csdn.net/willon_tom/article/details/4470197
Thread类
 
Thread类封装了POSIX标准中的多线程机制,提供了一种简单易用的线程模型。Thread类是Iperf的实现中比较重要的类,使Iperf实现多线程并行操作的核心。
Thread类的定义在文件lib/Thread.hpp中,其实现位于lib/Thread.cpp中。
/* ------------------------------------------------------------------- */
class Thread {
public:
    Thread( void );
    virtual ~Thread();
    // start or stop a thread executing
    void Start( void );
    void Stop( void );
    // run is the main loop for this thread
    // usually this is called by Start(), but may be called
    // directly for single-threaded applications.
    virtual void Run( void ) = 0;
    // wait for this or all threads to complete
    void Join( void );
    static void Joinall( void );
    void DeleteSelfAfterRun( void ) {
        mDeleteSelf = true;
    }
    // set a thread to be daemon, so joinall won't wait on it
    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:
    nthread_t mTID;
    bool mDeleteSelf;
    // count of threads; used in joinall
    static int sNum;
    static Condition sNum_cond;
private:
    // low level function which calls Run() for the object
    // this must be static in order to work with pthread_create
    static void*        Run_Wrapper( void* paramPtr );
}; // end class Thread
数据成员说明:
mTID纪录本线程的线程ID;
mDeleteSelf通过方法DeleteSelfAfterRun设置,用来说明是否在线程结束后释放属于该现程的变量;
sNum是一个静态变量,即为所有的Thread实例所共有的。该变量纪录所生成的线程的总数。Thread对象的Joinall方法通过该变量判断所有的Thread实例是否执行结束;
sNum_cond是用来同步对sNum的操作的条件变量,也是一个静态变量。
 
主要函数成员说明:

Start方法:
/* -------------------------------------------------------------------
 * Start the object's thread execution. Increments thread
 * count, spawns new thread, and stores thread ID.
 * ------------------------------------------------------------------- */
void Thread::Start( void ) {
    if ( EqualID( mTID, ZeroID() ) ) {
        // increment thread count
        sNum_cond.Lock();
        sNum++;
        sNum_cond.Unlock();
        Thread* ptr = this;
        // pthreads -- spawn new thread
        int err = pthread_create( &mTID, NULL, Run_Wrapper, ptr );
        FAIL( err != 0, "pthread_create" );
    }
} // end Start
首 先通过Num++纪录一个新的线程的产生,之后通过pthread_create系统调用产生一个新的线程。新线程执行Run_Wrapper函数,以至 向该Thread实例的ptr指针作为参数。原线程在判断pthread_create是否成功后退出Start函数。
 
Stop方法:
/* -------------------------------------------------------------------
 * Stop the thread immediately. Decrements thread count and
 * resets the thread ID.
 * ------------------------------------------------------------------- */
void Thread::Stop( void ) {
    if ( ! EqualID( mTID, ZeroID() ) ) {
        // decrement thread count
        sNum_cond.Lock();
        sNum--;
        sNum_cond.Signal();
        sNum_cond.Unlock();
        nthread_t oldTID = mTID;
        mTID = ZeroID();
        // exit thread
        // use exit()   if called from within this thread
        // use cancel() if called from a different thread
        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
首先通过sNum--纪录一个线程执行结束,并通过sNum_cond的Signal方法激活此时wait在 sNum_cond的线程(某个主线程会调用调用Joinall方法,等待全部线程的结束,在Joinall方法中通过sNum_cond.Wait() 等待在sNum_cond条件变量上)。若结束的线程是自身,则调用pthread_exit函数结束,否则调用pthread_cancel函数。注 意:传统的exit函数会结束整个进程(即该进程的全部线程)的运行,而pthread_exit函数仅结束该线程的运行。
 
Run_Wrapper方法:
/* -------------------------------------------------------------------
 * Low level function which starts a new thread, called by
 * Start(). The argument should be a pointer to a Thread object.
 * Calls the virtual Run() function for that object.
 * Upon completing, decrements thread count and resets thread ID.
 * If the object is deallocated immediately after calling Start(),
 * such as an object created on the stack that has since gone
 * out-of-scope, this will obviously fail.
 * [static]
 * ------------------------------------------------------------------- */
void*
Thread::Run_Wrapper( void* paramPtr ) {
    assert( paramPtr != NULL );
    Thread* objectPtr = (Thread*) paramPtr;
    // run (pure virtual function)
    objectPtr->Run();
#ifdef HAVE_POSIX_THREAD
    // 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);
#endif
    // 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
    sNum_cond.Lock();
    sNum--;
    sNum_cond.Signal();
    sNum_cond.Unlock();
    return NULL;
} // end run_wrapper
该方法是一个外包函数(wrapper),其主要功能是调用本实例的Run方法。实际上, Run_Wrapper是一个静态成员函数,是为所有的Thread实例所共有的,因此无法使用this指针。调用Run_Wrapper的Thread 是通过参数paramPtr指明具体的Thread实例的。在Run返回之后,通过pthread_detach使该线程在运行结束以后可以释放资源。 Joinall函数是通过监视sNum的数值等待所有线程运行结束的,而并非通过pthread_join函数。在完成清理工作后, Run_Wrapper减少sNum的值,并通过sNum_cond.Signal函数通知在Joinall中等待的线程。
Run方法:
从Run方法的声明中知道,该方法是一个纯虚函数,因此Thread是一个抽象基类,主要 作用是为其派生类提供统一的对外接口。在Thread的派生类中,像Iperf中的Server,Client,Speader,Audience, Listener等类,都会为Run提供特定的实现,完成不同的功能,这是对面向对象设计多态特性的运用。Thread函数通过Run方法提供了一个通用 的线程接口。
 
讨论: 为什么要通过Run_Wrapper函数间接的调用Run函数?
首先,Thread的各派生类的完成的功能不同,但它们都是Thread的实例,都有一些相同的工作要做,如初始化和清理等。在Run_Wrapper中实现这些作为Thread实例所应有的相同功能,在Run函数中实现派生类各自不同的功能,是比较合理的设计。
更重要的是,由于要通过Pthread_create函数调用Run_Wrapper函数,因此 Run_Wrapper函数必须是一个静态成员,无法使用this指针区分运行Run_Wrapper函数的具体实例,也就无法利用多态的特性。而这个问 题可以通过把this指针作为Run_Wrapper函数的参数,并在Run_Wrapper中显示调用具有多态特性的Run函数来解决。
这种使用一个wrapper函数的技术为我们提供了一种将C++面向对象编程和传统的Unix系统调用相结合的思路。
 
Joinall方法和SetDaemon方法:
/* -------------------------------------------------------------------
 * Wait for all thread object's execution to complete. Depends on the
 * thread count being accurate and the threads sending a condition
 * signal when they terminate.
 * [static]
 * ------------------------------------------------------------------- */
void Thread::Joinall( void ) {
    sNum_cond.Lock();
    while ( sNum > 0 ) {
        sNum_cond.Wait();
    }
    sNum_cond.Unlock();
} // end Joinall
/* -------------------------------------------------------------------
 * set a thread to be daemon, so joinall won't wait on it
 * this simply decrements the thread count that joinall uses,
 * which is not a thorough solution, but works for the moment
 * ------------------------------------------------------------------- */
void Thread::SetDaemon( void ) {
    sNum_cond.Lock();
    sNum--;
    sNum_cond.Signal();
    sNum_cond.Unlock();
}
由这两个方法的实现可见,Thread类是通过计数器sNum监视运行的线程数的。线程开始前(Start方法 中的pthread_create)sNum加一,线程结束后(Stop方法和Run_Wrapper方法末尾)sNum减一。Joinall通过条件变 量类的实例sNum_cond的Wait方法等待sNum的值改变。而SetDaemon的目的是使调用线程不再受主线程Joinall的约束,只是简单 的把sNum减一就可以了。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
【转】pthread多线程编程整理 - 与时间赛跑的使者
pthread的各种同步机制
Linux线程池(C语言描述)
浅析pthread_cond_wait
一个Linux下C线程池的实现
c++多线程编程
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服