Boost logo

Boost Users :

Subject: Re: [Boost-users] Threading question
From: Ulf Samuelsson (boost-user_at_[hidden])
Date: 2013-12-13 09:25:49


2013-09-27 01:48, Gavin Lambert skrev:
> On 9/27/2013 11:16 AM, Quoth Davies, John:
>> I have the following code and it terminates as expected. When I call the
>> destructor it interrupts the thread.
>>
>> But if I change the this_thread::sleep to this_thread::yield the join()
>> never happens and the program hangs.
>>
>> I must be misunderstanding yield. But I really don’t want a sleep if
>> possible.
>
> The main thing to remember about yield() is that it's permitted to be
> a no-op if the OS feels like it, and in particular on single-core
> systems it will completely block lower priority threads from running.
>
> Also note that unlike sleep, yield is not listed as an interruption
> point. So when you're using yield you're basically setting up a 100%
> CPU loop that can't be interrupted, which is why it's hanging. You
> *could* fix part of that by adding an explicit interruption point, but
> that's not the ideal solution.
>
> Given that it looks like you basically want to block until there's
> work to do in the queue, you might want to consider using a mutex and
> condition_variable (notifying the condition variable when you push
> something into the queue, and waiting on it when the queue is empty).
> You're going to need a mutex on the queue operations anyway unless
> you're using something that's internally thread-safe.
>
> You also might want to consider using something like Boost.Asio
> instead. Its io_service allows you to queue arbitrary function
> objects to a specific thread (or threadpool) in a thread-safe manner,
> even if you don't want to use the actual I/O parts.
>
>
Having problems with a three thread program.
The application is using Boost 1.54 on a Beaglebone Black ARM target.
using a single core Cortex-A8.

The first thread reads data from a serial port, and store a record with
the info in a list,
The second thread reads from the list, and upioads data from the list to
a webserver.
The list is protected by a boost::mutex Queue_Lock;

The third thread initializes the two first two threads and the ends up
executing

      io_service.run();

io_service is related to an UDP based debug channel using boost::asio.
By calling DebugPort.WriteLine you send a string to the UDP debug channel.
The UDP debug channel, is protected by another mutex, since both main
threads will use it.

THREAD_WRITE is a conditional DebugPort.WriteLine, and normally this is
a NOP.

The second thread calls a number of routines which tries to allocate
a mutex, and if not, it will yield.
It looks like the second thread hangs in one of these routines.
This does not occur frequently. The program was running for a week
before it happened the last time.

There is not enough debug prints right now to determine why, and since
the application was built using a cross compiler, there is not
a lot of symbols available.
When attaching using gdb, we saw that it was in a mutex wait in the
libpthread library

Typical code.

bool Server::QueueEmpty(void) {
     bool empty;
     try {
         THREAD_WRITE("Checking SendQueue", YELLOW);
         empty = true;
         while (1) {
             boost::mutex::scoped_lock lock(Queue_Lock, boost::try_to_lock);
             if (lock) {
                 empty = SendQueue.empty();
                 break;
             } else {
                 // Didn't get lock, retry after yield
                 THREAD_WRITE("Sendstart Yielding QueueEmpty", RED);
                 this_thread::yield();
                 THREAD_WRITE("Sendstart Returning QueueEmpty", RED);
             }
         }
     } catch (std::exception &e) {
         DebugPort.WriteLine(e.what(), RED);
         empty = true;
     }
     return empty;
}

Is there an obvious problem with this code?

It is using Yield, which I assumed was the right way to release the CPU.
Using sleep feels wrong, since I do not want to sleep, I want to wait
for the mutex.

The first thread implements the mutex in the same way, although not in a
subroutine.

Am I correct in assuming, that since I use scoped_lock, the mutex will
always be released when I exit the while loop with "break;"?

Best Regars
Ulf Samuelsson

> _______________________________________________
> Boost-users mailing list
> Boost-users_at_[hidden]
> http://lists.boost.org/mailman/listinfo.cgi/boost-users


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net