Line data Source code
1 : /**
2 : * @file ReusableThread.cpp Reusable thread wrapper
3 : * The same thread instance can be used with different tasks to be executed
4 : * Inspired by:
5 : * https://codereview.stackexchange.com/questions/134214/reuseable-c11-thread
6 : *
7 : * This is part of the DUNE DAQ , copyright 2020.
8 : * Licensing/copyright details are in the COPYING file that you should have
9 : * received with this code.
10 : */
11 :
12 : #include "utilities/ReusableThread.hpp"
13 : #include "utilities/Issues.hpp"
14 :
15 : #include <string>
16 :
17 374 : dunedaq::utilities::ReusableThread::ReusableThread(int threadid)
18 374 : : m_thread_id(threadid)
19 374 : , m_task_executed(true)
20 374 : , m_task_assigned(false)
21 374 : , m_thread_quit(false)
22 374 : , m_worker_done(false)
23 374 : , m_thread(&ReusableThread::thread_worker, this)
24 : {
25 374 : }
26 :
27 374 : dunedaq::utilities::ReusableThread::~ReusableThread()
28 : {
29 374 : while (m_task_assigned) {
30 0 : std::this_thread::sleep_for(std::chrono::milliseconds(1));
31 : }
32 374 : m_thread_quit = true;
33 1495 : while (!m_worker_done) {
34 747 : std::this_thread::sleep_for(std::chrono::milliseconds(1));
35 747 : m_cv.notify_all();
36 : }
37 374 : m_thread.join();
38 374 : }
39 :
40 : void
41 0 : dunedaq::utilities::ReusableThread::set_name(const std::string& name, int tid)
42 : {
43 0 : set_thread_id(tid);
44 0 : char tname[16]; // NOLINT
45 0 : snprintf(tname, 16, "%s-%d", name.c_str(), tid); // NOLINT
46 0 : auto handle = m_thread.native_handle();
47 0 : pthread_setname_np(handle, tname);
48 :
49 0 : m_named = true;
50 0 : }
51 :
52 : void
53 0 : dunedaq::utilities::ReusableThread::set_pin(int cpuid)
54 : {
55 : // Require that the thread has been named
56 0 : if (!m_named) {
57 0 : ers::warning(ThreadingIssue(ERS_HERE, "May not set CPU affinity for un-named thread"));
58 : }
59 :
60 0 : auto handle = m_thread.native_handle();
61 0 : cpu_set_t cpuset;
62 0 : CPU_ZERO(&cpuset);
63 0 : CPU_SET(cpuid, &cpuset);
64 0 : int rc = pthread_setaffinity_np(handle, sizeof(cpu_set_t), &cpuset);
65 :
66 0 : if (rc != 0) {
67 0 : ers::warning(ThreadingIssue(ERS_HERE, "Error calling pthread_setaffinity_np: " + std::to_string(rc)));
68 : }
69 0 : }
70 :
71 : void
72 374 : dunedaq::utilities::ReusableThread::thread_worker()
73 : {
74 374 : std::unique_lock<std::mutex> lock(m_mtx);
75 :
76 748 : while (!m_thread_quit) {
77 374 : if (!m_task_executed && m_task_assigned) {
78 1 : m_task();
79 1 : m_task_executed = true;
80 1 : m_task_assigned = false;
81 : } else {
82 373 : m_cv.wait(lock);
83 : }
84 : }
85 :
86 374 : m_worker_done = true;
87 374 : }
|