I am trying to implement a single producer (Main thread) and single consumer (Child Thread spawned from Main) problem, so as per my search I got spsc_queue
as the best lock-free data structure provided by boost library. Now taken from their example code, consumer function look likes this:
void consumer(void)
{
int value;
while (!done) {
while (queue.pop(value))
++consumer_count;
}
while (queue.pop(value))
++consumer_count;
}
Now, it may happen that the spsc_queue may remain empty for sometime
and so to avoid busy waiting, I introduced sleep in code like this:
void consumer(void)
{
int value;
while (!done) {
if (spsc_queue.empty())
{
cout << "Waiting for data....\n";
this_thread::sleep_for (chrono::milliseconds(100));
}
else
{
while (spsc_queue.pop(value))
{
++consumer_count;
}
}
}
while (spsc_queue.pop(value))
++consumer_count;
}
Is the correct way of doing it? Or, is there any better way to do it?
I came across some libraries such as libevent
or libev
or boost::asio::io_service
- Can someone help me out to figure out the best way to avoid busy waiting?
My concern is the performance and the code must be lock-free and wait-free (if possible). Any help would be appreciated.
答案 0 :(得分:1)
Your goal is not compatible with your requirements.
wait-free: waiting until an element is available already excludes this property.
lock-free: your goal is to not do any work until an element is available, i.e. you want to block. Again this contradicts both wait-free and lock-free.
What you DO actually want is something like
if (spsc_queue.empty()) {
doSomethingElse();
}
or simply, continue busy looping.
Maybe the closest to what you want is this:
if (spsc_queue.empty()) {
std::this_thread::yield();
}
which reschedules threads and lets other threads do their work. However, you are giving up your timeslice and might not get rescheduled earlier than 25-100ms.
Any specific reason why the code must be lock-free? Since the probability of your queue to be empty seems quite high, why do you need lock-free code? There is nothing to gain for you in that case.
On the other hand, if your probability of an empty queue is low, then the busy looping amortizes over time. You won't spend much time in the busy loop anyway but get your elements out as quick as you can (at the expense of an occasional busy wait).