Skip to content

Commit eb66991

Browse files
Fixed the race condition in NamedThread
Before this fix, `NamedThread::getCurrentThreadName()` might be called from the new thread (that already started executing) before the assignment to `thread_` in the `NamedThread` constructor had taken place. Then the query to the thread id (`nt->thread_.get_id()`) on such a thread did not return the correct id, and the end result was that a new (numbered) thread name was synthesized for that thread. From that point onward, concurrency orchestration via `log_debug()` (which relies on correct thread names) broke, typically resulting in a deadlock. This fix slightly reduces the generality of the `NamedThread` constructor (support for arguments to the callable has been dropped) since it is not currently needed (and even if it was needed, it could be circumvented with an extra lambda expression).
1 parent fe520a3 commit eb66991

File tree

2 files changed

+14
-4
lines changed

2 files changed

+14
-4
lines changed

src/namedthread.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,14 @@ namespace zim
3131
namespace
3232
{
3333

34-
std::mutex mutex_;
3534
size_t threadCounter_ = 0;
3635
std::vector<const NamedThread*> namedThreads_;
3736
std::map<std::thread::id, std::string> threadId2NameMap_;
3837

3938
} // unnamed namespace
4039

40+
std::mutex NamedThread::mutex_;
41+
4142
NamedThread::NamedThread(const std::string& name)
4243
: name_(name)
4344
{

src/namedthread.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#ifndef OPENZIM_LIBZIM_NAMEDTHREAD_H
2121
#define OPENZIM_LIBZIM_NAMEDTHREAD_H
2222

23+
#include <mutex>
2324
#include <string>
2425
#include <thread>
2526

@@ -34,11 +35,17 @@ class LIBZIM_PRIVATE_API NamedThread
3435
explicit NamedThread(const std::string& name);
3536

3637
public:
37-
template <class F, class... Args>
38-
NamedThread(const std::string& name, F&& f, Args&&... args)
38+
template <class F>
39+
NamedThread(const std::string& name, F&& f)
3940
: NamedThread(name)
4041
{
41-
thread_ = std::thread(std::forward<F>(f), std::forward<Args>(args)...);
42+
// Ensure that f starts executing after the assignment to
43+
// the thread_ data member has completed (so that any possible
44+
// calls to NamedThread::getCurrentThreadName() from inside f()
45+
// read the correct value of thread id).
46+
std::lock_guard<std::mutex> lock(mutex_);
47+
48+
thread_ = std::thread([f]() { mutex_.lock(); mutex_.unlock(); f(); });
4249
}
4350

4451
~NamedThread();
@@ -53,6 +60,8 @@ class LIBZIM_PRIVATE_API NamedThread
5360
private:
5461
const std::string name_;
5562
std::thread thread_;
63+
64+
static std::mutex mutex_;
5665
};
5766

5867
} // namespace zim

0 commit comments

Comments
 (0)