• c++ 线程类


            在 C++11 发布前,C++语言本身并不支持线程,而是通过 pthread 库来进行支持的,C++11发布后,其语言本身已经支持了线程,且是通过线程类的方式进行提供,使用方法可能参考此篇文章:c++11线程类 。现在C++11及之后版本已经提供了线程类来使用线程,但我们在编译的时候还是需要添加 -lpthread 链接(也许其线程类实现还是得依赖 pthread 库吧,没看过源码还不清楚),那如果不使用c++提供的线程类,我们在实际项目中是如何封装的线程类呢?

            以下代码先以 muduo 库里的线程类进行一下讲解,看它是如何封装线程类的,如:

    1. #ifndef __UNI_THREAD_H__
    2. #define __UNI_THREAD_H__
    3. #include
    4. #include
    5. #include
    6. class CThread: public boost::noncopyable
    7. {
    8. public:
    9. typedef boost::function0<void> threadProc;
    10. explicit CThread(const threadProc& proc, std::string threaName);
    11. ~CThread();
    12. void createThread();
    13. bool started()const
    14. {
    15. return mStarted;
    16. }
    17. pid_t tid() const
    18. {
    19. return mTid;
    20. }
    21. const std::string& name()const
    22. {
    23. return mName;
    24. }
    25. int join();
    26. private:
    27. static void* startThread(void* arg);
    28. void runInThread();
    29. private:
    30. bool mStarted;
    31. pthread_t mPthreadId;
    32. pid_t mTid;
    33. threadProc funcProc;
    34. std::string mName;
    35. };
    36. #endif

     这是一个线程类的声明,我们看到此类构造函数里就可以绑定要执行的线程函数。它的实现是这样的:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include "Thread.h"
    6. #include "CurrentThread.h"
    7. namespace detail
    8. {
    9. pid_t gettid()
    10. {
    11. return static_cast<pid_t>(::syscall(SYS_gettid));
    12. }
    13. };
    14. /*****************************
    15. * namespace CurrentThread
    16. * **************************/
    17. namespace CurrentThread
    18. {
    19. __thread int tCachedTid = 0;
    20. __thread char tTidString[32];
    21. __thread const char *tThreadName = "unknow";
    22. };
    23. void CurrentThread::cacheTid()
    24. {
    25. ///第一次调用时会调用系统函数
    26. if(tCachedTid == 0)
    27. {
    28. tCachedTid = detail::gettid();
    29. snprintf(tTidString, sizeof(tTidString), "%5d ", tCachedTid);
    30. }
    31. }
    32. bool CurrentThread::isMainThread()
    33. {
    34. return tid() == ::getpid();
    35. }
    36. /*****************************
    37. * CThread
    38. * **************************/
    39. CThread::CThread(const threadProc& proc, std::string threaName):
    40. mStarted(false),
    41. mPthreadId(-1),
    42. funcProc(proc),
    43. mName(threaName)
    44. {
    45. }
    46. CThread::~CThread()
    47. {
    48. }
    49. void CThread::createThread()
    50. {
    51. assert(!mStarted);
    52. mStarted = true;
    53. errno = pthread_create(&mPthreadId, NULL, startThread, this);
    54. if(errno < 0)
    55. {
    56. }
    57. }
    58. void* CThread::startThread(void* arg)
    59. {
    60. CThread *thread = static_cast(arg);
    61. thread->runInThread();
    62. return nullptr;
    63. }
    64. void CThread::runInThread()
    65. {
    66. mTid = CurrentThread::tid();
    67. if(funcProc)
    68. {
    69. funcProc();
    70. }
    71. }
    72. int CThread::join()
    73. {
    74. assert(mStarted);
    75. return pthread_join(mPthreadId, nullptr);
    76. }

    可以看到在 createThread() 成员函数里调用了 pthread_create() 进行线程的创建,而且线程函数是此类的一个 static 函数 startThread(void* arg),为什么是 static 类型函数呢?因为函数 pthread_create() 的第 3 个参数是一个函数指针,且是 C 语言类型的函数指针,这里无法传入类的成员函数。实际工作中遇到的是另外一种实现方法,后面会有介绍。所以使用时,只要定义一个CThread 对象,然后调用 createThread() 即可,如:

    在 调用 CAsyncLogging::start() 后,线程即刻创建起来,且执行线程函数 threadProc()。

    实际工作中遇到线程类是这样的,列举片段:

    1. // 线程类的声明
    2. class CThread
    3. {
    4. ///其他成员函数
    5. bool createThread();
    6. /// 线程执行体,是一个纯虚函数,派生的线程类中必须实现此函数,实现各自的行为。
    7. virtual void threadProc() = 0;
    8. }

    这里最重要的是声明了一个纯虚函数,说明这个类是一个抽象类,只能用作基类。它也有一个 public 成员函数 createThread(),通过此函数创建线程,但这里比上面那个 createThread() 复杂一点,它里面会设置线程的属性、调度策略、线程优先级、线程栈大小等。 

    ret = pthread_create(&mInternal->mHandle, &attr, threadBody, (void *)mInternal);

     它的线程函数也是一个全局函数,最后一个是一个内部的对象,保存着这个线程的相关信息。在线程函数里首先会把这个参数强转成指定类型,然后再进行调用。

    pInternal->mOwner->threadProc();

    而这个mOwner 就是在CThread 的构造函数里被赋为了 this,就是CThread对象,派生类只要实现 virtual void threadProc(),然后调用 createThread() 后就可以调用到自己的 threadProc() 函数了,这里用到的就是类的虚函数特性了。使用起来也很方便:

    1. #include "Thread.h"
    2. #include
    3. #include
    4. #include
    5. class CMyThread: public CThread
    6. {
    7. public:
    8. CMyThread();
    9. ~CMyThread();
    10. virtual void threadProc();
    11. };
    12. CMyThread::CMyThread(): CThread("myThread")
    13. {
    14. }
    15. CMyThread::~CMyThread()
    16. {
    17. }
    18. void CMyThread::threadProc()
    19. {
    20. int count = 5;
    21. while(count--)
    22. {
    23. sleep(1);
    24. printf("in CMyThread\n");
    25. }
    26. }
    27. int main()
    28. {
    29. CMyThread *myThread = new CMyThread();
    30. myThread->createThread();
    31. sleep(7);
    32. return 0;
    33. }

    派生类里只要实现 threadProc() 即可,运行结果如:

  • 相关阅读:
    【集合】双列集合
    数字化时代,低代码是企业的未来共识吗?
    数据结构的奥秘:算法与实际应用的完美融合
    玩转 GPT4All
    5G将如何改变我们的生活
    Linux系统IO
    【记录】IDA|IDA怎么查看当前二进制文件自动分析出来的内存分布情况(内存范围和读写性)
    编程语言介绍
    俄罗斯人有哪些商务礼仪
    数据分析三剑客-Matplotlib
  • 原文地址:https://blog.csdn.net/tianyexing2008/article/details/126864935