patterncppMinor
Thread worker simulator
Viewed 0 times
simulatorthreadworker
Problem
Because I have been writing more multithreaded C++14 code lately, I've developed some tools that help me make sure that my threads are all working as intended. In the real code, it's often difficult to detect race conditions or unintended sequence dependencies among threads, so I have found that temporarily substituting a work simulator (
There are three main pieces in the code below. The first is the
The second piece is the
The third piece is a simple
I'm interested in comments on the
threadplay.cpp
```
#include
#include
#include
#include
#include
#include
#include
#include
class Logger {
public:
Logger &operator lock(m);
std::cout &stop, int n) {
using namespace std::chrono_literals;
static std::mt19937 gen(std::random_device{}());
std::binomial_distribution dist(50, 0.5);
std::stringstream ss;
ss stop{false};
std::vector th;
Logger mylog;
for (int i=0; i<10; ++i) {
th.push_back(std::thread(worksim, std::ref(mylog), std::ref(stop),
worksim in the code) for the real thread code, leaving any other locks, mutexes, etc. in place, allows me to gain some insight as to how the various threads might run. There are three main pieces in the code below. The first is the
Logger class which is more or less a mutex-protected interface to std::cout. It takes a std::stringstream & as input, emits the contents of it to std::cout and the clears the input stringstream.The second piece is the
worksim itself which employs a binomial random number distribution to generate delays that are typically around 25ms, emitting status to the passed Logger object until the stop flag is set. I deliberately do not want to use a conditional variable here because I want to simulate the work that the thread would do.The third piece is a simple
main showing how these are used. It creates 10 threads, waits five seconds and then shuts everything down. I'm interested in comments on the
worksim portion in particular. Specifically,- is the intent clear?
- is the use of a
staticnumber generator OK here?
- is there a better way to handle the logging?
threadplay.cpp
```
#include
#include
#include
#include
#include
#include
#include
#include
class Logger {
public:
Logger &operator lock(m);
std::cout &stop, int n) {
using namespace std::chrono_literals;
static std::mt19937 gen(std::random_device{}());
std::binomial_distribution dist(50, 0.5);
std::stringstream ss;
ss stop{false};
std::vector th;
Logger mylog;
for (int i=0; i<10; ++i) {
th.push_back(std::thread(worksim, std::ref(mylog), std::ref(stop),
Solution
- Is the intent clear?
Not completely for me. As you're saying
for the real thread code, leaving any other locks, mutexes, etc. in place, allows me to gain some insight as to how the various threads might run.
the closest intent I can grasp is, you want to eliminate certain threads by replacing them with
worksim threads, to isolate other threads that might be the source of race conditions, dead locks or other multiple threading related problems in the to be tested code.I'm not a 100% sure if these simplified threads may be really useful for diagnosis of the above mentioned problems. Especially as they won't affect other threads, other than with a random delay and don't touch those synchronization mechanisms left in place. To some degree may be.
- Is the use of a static number generator OK here?
The instantiation of static local variables will be thread safe. Execution of operations like
dist(gen)) will not guarantee thread safety.The reference documentation about
std::binomial_distribution::operator() doesn't tell anything about thread safety, and because gen is a shared resource between threads I would doubt about appropriate results.- is there a better way to handle the logging?
The standard I/O output can be fairly slow, and as I mentioned in my comment "The use of a shared logger with the mutex locking may severely influence your threads' runtime behavior".
A generally better approach might be to use the shortest possible lock to pass the log message to the logger (e.g. using a protected queue of
std::unique_ptr's), and let the Logger class output these from another background thread (that's what we're using in our production systems).Context
StackExchange Code Review Q#151342, answer score: 2
Revisions (0)
No revisions yet.