Reputation: 32635
Consider a system in which a bunch of threads waits for some transactions to complete (note that more than one thread can wait for a single transaction). In order for the transactions to complete, one of the threads must run a dispatch loop. Once the transaction being waited upon by the thread currently running the dispatch loop completes, one of the other threads must take over the job.
On Windows, this is easily implemented: for each transaction, there is a manual-reset event that is set when the transaction completes. Furthermore, there is an auto-reset event that is set when the dispatch loop exits. Each thread waits simultaneously on both events. Either the transaction event is signaled first -- in which case the thread exits -- or the loop event -- in which case the thread runs the dispatch loop.
How do I implement this on Linux (or better yet, Posix)? Currently, I've replaced the events from above with bool
variables and I have a condition variable to signal that one of them changed. However, in this arrangement, threads wake up spuriously (whenever one of the transactions complete, all of the threads wake up). Is there a way to implement this better?
Upvotes: 1
Views: 1370
Reputation: 70382
I might have misunderstood your requirement. I would create an abstraction for an event, and have a single event queue. Derived events would be enqueued, and the threads are waiting for the condition that the queue be non-empty. An enqueue would cause a signal on a condition variable.
struct AnEvent {
int type_;
union {
//...
};
};
struct EventQ {
std::mutex m_;
std::condition_variable c_;
std::list<AnEvent> q_;
void enq (const AnEvent &e) {
std::lock_guard<std::mutex> g(m_);
bool was_empty = q_.empty();
q_.push_back(e);
if (was_empty) c_.notify_one();
};
void deq (AnEvent &e) {
std::lock_guard<std::mutex> g(m_);
while (q_.empty()) c_.wait(m_);
e = q_.top();
q_.pop_front();
if (!q_.empty()) c_.notify_one();
}
Upvotes: 0
Reputation: 239011
I may not have got your scenario completely clear, but I think you could use one condition variable per transaction (but still a single mutex).
When the transaction finishes, its corresponding condition variable is signalled; when the dispatch loop exits, all the condition variables are signalled.
Upvotes: 4