zoukankan      html  css  js  c++  java
  • 【C/C++开发】C++ Thread对象封装

    Pthread库是posix linux的线程库,调用接口如下,我们模仿JDK,对Thread进行封装,具体的业务逻辑只需要如同Thread一样实现run方法即可。

    线程操纵函数(简介起见,省略参数)

    pthread_create():创建一个线程
    pthread_exit():终止当前线程
    pthread_cancel():中断另外一个线程的运行
    pthread_join():阻塞当前的线程,直到另外一个线程运行结束
    pthread_attr_init():初始化线程的属性
    pthread_attr_setdetachstate():设置脱离状态的属性(决定这个线程在终止时是否可以被结合)
    pthread_attr_getdetachstate():获取脱离状态的属性
    pthread_attr_destroy():删除线程的属性
    pthread_kill():向线程发送一个信号

     
     首先,构造一个run接口如下:

    class TC_Runable
    {
    public:
        virtual ~TC_Runable(){};
        virtual void run() = 0;
    };


    声明线程基础类:
    /**
     * 线程基类.
     * 线程基类,所有自定义线程继承于该类,同时实现run接口即可,  
     * 可以通过TC_ThreadContorl管理线程。
     */
    class TC_Thread : public TC_Runable
    {
    public:

         /**
         * @brief  构造函数
          */
         TC_Thread();

         /**
         * @brief  析构函数
          */
         virtual ~TC_Thread(){};

         /**
         * @brief  线程运行
          */
         TC_ThreadControl start();

        /**
         * @brief  获取线程控制类.
         *
         * @return ThreadControl
         */
        TC_ThreadControl getThreadControl() const;

        /**
         * @brief  线程是否存活.
         *
         * @return bool 存活返回true,否则返回false
         */
        bool isAlive() const;

         /**
         * @brief  获取线程id.
          *
          * @return pthread_t 线程id
          */
         pthread_t id() { return _tid; }

    protected:

         /**
          * @brief  静态函数, 线程入口.
          * 
          * @param pThread 线程对象
          */
         static void threadEntry(TC_Thread *pThread);

         /**
         * @brief  运行
          */
        virtual void run() = 0;

    protected:
        /**
         * 是否在运行
         */
        bool            _running;

        /**
         * 线程ID
         */
        pthread_t      _tid;

        /**
         * 线程锁
         */
        TC_ThreadLock   _lock;
    };

    根据Pthread提供的接口实现该Thread类。

    线程构造函数:
    TC_Thread::TC_Thread() : _running( false), _tid(-1)
    {
    }
    初始化tid为-1,线程状态running为false。


    线程执行入口,该方法声明的时候必须为静态方法,因为该方法符合pthread_create方法中的函数指针的类型,该方法将会回调thread的具体的子类重载的run方法,thread子类的实例通过指针传递进来。

    void TC_Thread::threadEntry( TC_Thread *pThread)
    {
        pThread->_running = true;

        {
            TC_ThreadLock::Lock sync(pThread-> _lock);
            pThread-> _lock.notifyAll();
        }

        try
        {
            pThread->run();
        }
        catch(...)
        {
            pThread-> _running = false;
            throw;
        }
        pThread->_running = false;
    }


    通过调用start方法线程开始执行,但并不负责具体的执行逻辑,所以该方法对于start来说是通过的,是调用pthread_ctreat的地方,在该方法中,会调用this.threadEntity函数,通过其回调this.run()
    TC_ThreadControl TC_Thread::start()
    {
        TC_ThreadLock::Lock sync(_lock);

        if(_running)
        {
            throw TC_ThreadThreadControl_Exception("[TC_Thread::start] thread has start");
        }

        int ret = pthread_create(&_tid ,
                       0,
                       ( void *(*)( void *))& threadEntry,
                       ( void *) this);

        if(ret != 0)
        {
            throw TC_ThreadThreadControl_Exception("[TC_Thread::start] thread start error", ret);
        }

        _lock.wait();

        return TC_ThreadControl(_tid);
    }


    获取线程控制工具类
    TC_ThreadControl TC_Thread::getThreadControl () const
    {
        return TC_ThreadControl(_tid);
    }


    判断线程当前状态。
    bool TC_Thread::isAlive() const
    {
        return _running;
    }

    整个线程类封装设计的难点在于,如果保证running的同步,我们必须保证线程真正在执行run方法的时候,该running设置为true,也就是说不能单纯的在start中变更该状态,因为此时有可能threadEntity并没有被执行(Pthread_creat)



    在start方法中,首先便获取锁并顺序执行,但是start方法并不返回将wait住(3)(因为此事线程提方法并不一定成功执行,也就是说start能够返回的标志是该线程状态必须为running,否则在业务层面执行完start方法紧接着判断线程isalive却返回false会给调用者带来迷茫,甚至导致重复启动),threadEntity执行时表明pthread_create方法已经开始执行了,新线程执行OK,此时该方法将running设置为true(1),并且试图获取锁,此时如果wait已经执行,则获取锁操作可以成功,如果wait不成功,则会阻塞在这里等待wait操作的到来释放锁。

        {
            TC_ThreadLock::Lock sync(pThread-> _lock);
            pThread-> _lock.notifyAll();
        }

    这个大括号很重要,表示sync的生命周期在大括号结束的时候会释放,锁释放代表着notifyAll生效(真正的通知wait解除阻塞是在锁释放的时候进行的,因为wait需要重新获取锁),此时running为true,start方法可以安全返回了。当方法进行完之后,将running重新设置为false(2)。

  • 相关阅读:
    SQL数据转移
    怎么将控制台的打印输出到文本文件中
    用来控制 XML 序列化的属性
    excel内容转成xml
    HTTP状态码
    char、varchar、nchar、nvarchar的区别
    C# Cookie编程
    android的原理--为什么我们不需要手动关闭程序
    HTTP协议及HTTP包
    HTTP 方法:GET 对比 POST
  • 原文地址:https://www.cnblogs.com/huty/p/8517385.html
Copyright © 2011-2022 走看看