博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Iperf 源代码分析(二)
阅读量:5972 次
发布时间:2019-06-19

本文共 7987 字,大约阅读时间需要 26 分钟。

hot3.png

Thread 

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

    Thread类的定义在文件lib/Thread.hpp中,其实现位于lib/Thread.cpp中。

//Thread.hppclass 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;#if   defined( HAVE_POSIX_THREAD )        // pthreads -- spawn new thread        int err = pthread_create( &mTID, NULL, Run_Wrapper, ptr );        FAIL( err != 0, "pthread_create" );#elif defined( HAVE_WIN32_THREAD )        // Win32 threads -- spawn new thread        // Win32 has a thread handle in addition to the thread ID        mHandle = CreateThread( NULL, 0, Run_Wrapper, ptr, 0, &mTID );        FAIL_errno( mHandle == NULL, "CreateThread" );#else        // single-threaded -- call Run_Wrapper in this thread        Run_Wrapper( ptr );#endif    }} // end Start

    首先通过sNum++纪录一个新的线程的产生,之后通过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();#ifdef HAVE_THREAD        nthread_t oldTID = mTID;        mTID = ZeroID();        // exit thread#if   defined( HAVE_POSIX_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#ifdef HAVE_PTHREAD_CANCEL            pthread_cancel( oldTID );#endif        }#elif defined( HAVE_WIN32_THREAD )        if ( EqualID( GetID(), oldTID ) ) {            ExitThread( 0 );        } else {            // this is a somewhat dangerous function; it's not            // suggested to Stop() threads a lot.            TerminateThread( mHandle, 0 );        }#endif#endif    }} // 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] * ------------------------------------------------------------------- */#if   defined( HAVE_WIN32_THREAD )DWORD WINAPI#elsevoid*#endifThread::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方法:

/*Thread.hpp*/        // 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;

    从Run方法的声明中知道,该方法是一个纯虚函数,因此Thread是一个抽象基类,主要作用是为其派生类提供统一的对外接口。在Thread的派生类中,像Iperf中的ServerClientSpeaderAudienceListener等类,都为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加1,线程结束后(Stop方法和 Run_Wrapper方法末尾),sNum减1。Joinall通过条件变量类的实例sNum_cond的Wait方法等待sNum的值改变,而SetDaemon的目的是使调用线程不再受主线程Joinall的约束,只是简单的把sNum减1就可以了。

转载于:https://my.oschina.net/kiterunner24/blog/268798

你可能感兴趣的文章
埃森哲:2017年网络犯罪成本研究报告(含分析)
查看>>
SQL Server 2008备份策略设计上(五)
查看>>
开发可统计单词个数的Android驱动程序(2)
查看>>
【VMCloud云平台】私有云门户第一朵VM云(二)
查看>>
XCode编译运行出错解决思路,以及再次推荐AppCode
查看>>
活动分区丢失导致的Windows 8无法启动
查看>>
我在赶集网的两个月 (完整版)
查看>>
SFB 项目经验-08-Polycom CX700-4.0.X-能登录SFB 2015-能更新为中文
查看>>
我的友情链接
查看>>
新浪微博广告,要社交还是要品牌?
查看>>
Twisted入门教程(1、2)
查看>>
自动化日吸1000粉的流程和思路:内含3个案例和实操
查看>>
要么死,要么骗,移动互联网无机会
查看>>
NetApp携手长虹佳华共绘云版图
查看>>
【干货】从QQ群起家的情趣商城站长之路
查看>>
Spread表格组件For JAVA功能介绍—表格相关操作
查看>>
下馆子的十个温馨小提示。
查看>>
具有超级牛力的dd命令-详解。
查看>>
QoS技术入门(实操必须掌握的基本理论)
查看>>
不同系统查WWN号
查看>>