适配qnx和linux平台的线程管理类封装

概述

封装代码仓库: https://gitee.com/liudegui/my_thread

尝试封装一个基于C++11的多线程控制与调度类,适配QNX和Linux平台,且代码符合Misra标准。它提供了以下主要功能:

  • 线程的创建与销毁管理。
  • 线程的优先级调度。
  • 线程的CPU亲和性设置。
  • 线程的等待与唤醒机制。

类的结构及主要成员函数如下:

  • 构造函数与析构函数:负责初始化线程相关参数,并在析构时确保线程安全退出。
  • thread_start():启动线程,创建指定数量的线程实例。
  • thread_shutdown():关闭线程,释放资源并等待所有线程退出。
  • timed_wait():线程的超时等待机制,防止线程无限等待。
  • set_self_thread_priority():设置当前线程的优先级。

实现细节

MyThread类内部实现主要涉及以下几个方面:

  • 使用std::thread来创建线程实例。
  • 利用std::mutex和std::condition_variable来实现线程同步。
  • 使用pthread库来设置线程的优先级和CPU亲和性。
cpp 复制代码
/**
* my_thread.h
*/

#ifndef UTILS_MY_THREAD_H_
#define UTILS_MY_THREAD_H_

#include <atomic>
#include <cstdint>
#include <functional>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include <condition_variable>
#include <memory>


namespace MyTest {
class MyThread {
 public:
  explicit MyThread(const std::string& in_name, int32_t in_priority, uint32_t in_worker_num,
                     const std::function<void()> in_func, int32_t in_cpusetsize, const cpu_set_t*const in_cpuset);
  ~MyThread();
  void thread_start();
  void thread_shutdown();
  bool has_shutdown() const {
    return is_shutdown_;
  }
  void timed_wait(uint32_t useconds);
  static void set_self_thread_priority(int32_t in_priority);

 private:
  static void my_thread_func_(MyThread* thread_ins);

 private:
  std::string thread_name_;
  int32_t thread_priority_;
  uint32_t thread_worker_num_;
  std::vector<std::shared_ptr<std::thread>> my_threads_;
  std::function<void()> func_main_;
  int32_t thread_cpusetsize_;
  const cpu_set_t* thread_cpuset_ = nullptr;
  std::mutex thread_mutex_;
  std::condition_variable thread_cond_;
  bool is_shutdown_;
};

}  // namespace MyTest

#endif  // UTILS_MY_THREAD_H_
cpp 复制代码
/**
* my_thread.cpp
*/

#include "my_thread.h"

#include <ctime>
#include <sstream>
#ifndef _QNX_
#include <sys/syscall.h>
#endif
#include <sys/types.h>
#include "fake_log.h"

namespace MyTest {

MyThread::MyThread(const std::string& in_name, int32_t in_priority, uint32_t in_worker_num,
                   const std::function<void()> in_func, int32_t in_cpusetsize, const cpu_set_t* const in_cpuset)
    : thread_name_(in_name),
      thread_priority_(in_priority),
      thread_worker_num_(in_worker_num),
      func_main_(in_func),
      thread_cpusetsize_(in_cpusetsize),
      thread_cpuset_(in_cpuset),
      is_shutdown_(true) {
}

MyThread::~MyThread() {
  if (!is_shutdown_) {
    thread_shutdown();
  }
}

void MyThread::my_thread_func_(MyThread* thread_ins) {
  if (thread_ins == nullptr) {
    MY_LOG_ERROR("thread_ins is nullptr");
  } else {
#ifndef _QNX_
    if ((thread_ins->thread_cpuset_ != nullptr) && (thread_ins->thread_cpusetsize_ > 0)) {
      const pthread_t tid = pthread_self();
      const auto np_return =
          pthread_setaffinity_np(tid, static_cast<size_t>(thread_ins->thread_cpusetsize_), thread_ins->thread_cpuset_);
      if (np_return != 0) {
        MY_LOG_ERROR("pthread_setaffinity_np failed. return=%d", np_return);
      }
    }
#else
    // qnx ...
#endif
    std::stringstream thread_id_stream;
    thread_id_stream << std::this_thread::get_id();

    MY_LOG_INFO("thread %s starts. pid=%s target_priority=%d", thread_ins->thread_name_.c_str(),
                thread_id_stream.str().c_str(), thread_ins->thread_priority_);
    MyThread::set_self_thread_priority(thread_ins->thread_priority_);
    try {
      thread_ins->func_main_();
    } catch (...) {
      MY_LOG_ERROR("Exception occurred in thread %s", thread_ins->thread_name_.c_str());
    }
  }
}

void MyThread::thread_start() {
  std::lock_guard<std::mutex> lck(thread_mutex_);
  is_shutdown_ = false;
  my_threads_.resize(thread_worker_num_);
  uint32_t thread_idx = 0;
  for (; thread_idx < thread_worker_num_; thread_idx++) {
    my_threads_[thread_idx] = std::make_shared<std::thread>(my_thread_func_, this);
  }
}

void MyThread::thread_shutdown() {
  std::lock_guard<std::mutex> lck(thread_mutex_);
  if (!is_shutdown_) {
    is_shutdown_ = true;
    thread_cond_.notify_all();

    for (const auto& my_t : my_threads_) {
      if (my_t->joinable()) {
        my_t->join();
      }
    }
  }
}

void MyThread::timed_wait(uint32_t useconds) {
  std::unique_lock<std::mutex> lck(thread_mutex_);
  const auto timeout_val = std::chrono::microseconds(useconds);
  do {
    const auto return_val = thread_cond_.wait_for(lck, timeout_val);
    if (return_val == std::cv_status::timeout) {
      MY_LOG_ERROR("thread timed_wait timeout");
    }
  } while (false);
}

void MyThread::set_self_thread_priority(int32_t in_priority) {
  bool go_on = true;
  struct sched_param params;
  struct sched_param current_params;
  int32_t set_policy{0};
  int32_t current_policy{0};
  const pthread_t this_thread = pthread_self();

  int32_t status_ret = pthread_getschedparam(this_thread, &current_policy, &current_params);
  if (status_ret != 0) {
    MY_LOG_ERROR("getschedparam %d", status_ret);
    go_on = false;
  } else {
    MY_LOG_DEBUG("thread current priority is %d (%d), target is %d", current_params.sched_priority, current_policy,
                 in_priority);  // MY_LOG_TRACE
    if (in_priority == 0) {
      go_on = false;
    } else if (in_priority > 0) {
      set_policy = SCHED_FIFO;
      params.sched_priority = current_params.sched_priority + in_priority;
    } else {
      set_policy = SCHED_IDLE;
      params.sched_priority = 0;
    }
  }
  if (go_on) {
    if (params.sched_priority > 99) {
      params.sched_priority = 99;
    }
    if (params.sched_priority < 0) {
      params.sched_priority = 0;
    }
    status_ret = pthread_setschedparam(this_thread, set_policy, &params);
    if (status_ret != 0) {
      MY_LOG_WARN("setschedparam(%d)", params.sched_priority);
      go_on = false;
    }
  }

  if (go_on) {
    status_ret = pthread_getschedparam(this_thread, &current_policy, &current_params);
    if (status_ret != 0) {
      MY_LOG_ERROR("getschedparam 2 %d", status_ret);
    } else {
      if (current_params.sched_priority != params.sched_priority) {
        MY_LOG_ERROR("current priority=%d (%d), target is %d", current_params.sched_priority, current_policy,
                     params.sched_priority);
      } else {
        MY_LOG_INFO("set thread priority to %d (%d)", current_params.sched_priority, current_policy);
      }
    }
  }
}

}  // namespace MyTest

测试代码

cpp 复制代码
#include "my_thread.h"

#include <chrono>
#include <iostream>
#include <string>

namespace MyTest {
static void worker_function() {
  std::this_thread::sleep_for(std::chrono::milliseconds(100));
  std::cout << "Thread ID: " << std::this_thread::get_id() << " is working." << std::endl;
}
}  // namespace MyTest

int32_t main() {
  int32_t main_res{0};

  try {
    const uint32_t num_threads = 4;

    cpu_set_t cpuset1;
    CPU_ZERO(&cpuset1);
    CPU_SET(0, &cpuset1);

    std::vector<std::shared_ptr<MyTest::MyThread>> test_threads;
    uint32_t thread_idx = 0;
    for (; thread_idx < num_threads; ++thread_idx) {
      const std::string thread_name1 = std::string("Thread_") + std::to_string(thread_idx);
      const std::shared_ptr<MyTest::MyThread> my_t = std::make_shared<MyTest::MyThread>(
          thread_name1, 1, 1, MyTest::worker_function, sizeof(cpuset1), &cpuset1);
      test_threads.push_back(my_t);
    }

    for (const auto& my_t : test_threads) {
      my_t->thread_start();
    }

    std::this_thread::sleep_for(std::chrono::seconds(2));

    for (const auto& my_t : test_threads) {
      my_t->thread_shutdown();
    }
    for (const auto& my_t : test_threads) {
      while (!my_t->has_shutdown()) {
        // std::this_thread::yield();
        my_t->timed_wait(100);
      }
    }
    std::cout << "All threads have been shutdown." << std::endl;
  } catch (...) {
    std::cerr << "Exception occurred" << std::endl;
    main_res = 1;
  }
  return main_res;
}
相关推荐
老猿讲编程2 天前
Python 线程学习知识大全
python·线程
邂逅岁月4 天前
【多线程奇妙屋】 Java 的 Thread类必会小技巧,教你如何用多种方式快速创建线程,学并发编程必备(实践篇)
java·开发语言·操作系统·线程·进程·并发编程·javaee
wangsir.4 天前
POSIX信号量
linux·c++·线程·信号处理·进程
CXDNW5 天前
【系统面试篇】进程和线程类(1)(笔记)——区别、通讯方式、同步、互斥、死锁
笔记·操作系统·线程·进程·互斥·死锁
wangsir.6 天前
linux线程池
linux·c++·线程
Java 第一深情7 天前
网络编程基础-Reactor线程模型-原理剖析
网络编程·线程·io模型
Themberfue7 天前
Java多线程详解③(全程干货!!!)Thread Runnable
java·开发语言·学习·线程·多线程
萤火虫Coding7 天前
Android Handler消息机制(五)-HandlerThread完全解析
android·thread·handler·handlerthread
wangsir.8 天前
线程的同步
linux·服务器·线程·同步
Winston Wood11 天前
十分钟了解Android Handler、Looper、Message
android·线程·多线程