Forum: GNU Radio Thread Synchronization

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
121f303ed62e30b569097a3d16825a94?d=identicon&s=25 Tom Lutz (Guest)
on 2009-05-12 21:23
(Received via mailing list)
I'm editing some of the .cc files and would like to know the preferred
method for performing thread synchronization in C++ code.  In
particular, I
noticed that the set and get methods that are called on the
gr_oscope_guts
class originate from a different thread then that of process_samples,
and
this is causing problems for me.

Thanks,
Tom
745d8202ef5a58c1058d0e5395a78f9c?d=identicon&s=25 Eric Blossom (Guest)
on 2009-05-12 22:10
(Received via mailing list)
On Tue, May 12, 2009 at 03:22:47PM -0400, Tom Lutz wrote:
> I'm editing some of the .cc files and would like to know the preferred
> method for performing thread synchronization in C++ code.  In particular, I
> noticed that the set and get methods that are called on the gr_oscope_guts
> class originate from a different thread then that of process_samples, and
> this is causing problems for me.
>
> Thanks,
> Tom

Please use the boost mutexs:

  #include <boost/thread.hpp>

  boost::mutex  m;      // the mutex

  boost::mutex::scoped_lock guard(m)  // the scoped guard

Eric
121f303ed62e30b569097a3d16825a94?d=identicon&s=25 Tom Lutz (Guest)
on 2009-05-12 22:38
(Received via mailing list)
On Tue, May 12, 2009 at 4:09 PM, Eric Blossom <eb@comsec.com> wrote:

> > Tom
>
> Please use the boost mutexs:
>
>  #include <boost/thread.hpp>
>
>  boost::mutex  m;                      // the mutex
>
>  boost::mutex::scoped_lock guard(m)    // the scoped guard
>
> Eric


Thanks a bunch!
Tom
121f303ed62e30b569097a3d16825a94?d=identicon&s=25 Tom Lutz (Guest)
on 2009-05-13 21:34
(Received via mailing list)
>
Would it severely affect performance to create a
boost::mutex::scoped_lock
inside the function gr_oscope_guts::process_sample?  It looks to me as
if
this would hurt performance because this function is called for every
single
sample the scope receives.  If a boost::mutex is based on an OS
primitive
that requires a syscall.....could be sloow.

The reason I'd like to place a mutex in this function is so that the
buffers
can be resized per user preference while the scope is running.  In my
case,
I needed more than 2048 samples, so I'm working on making the scope with
a
configurable output record size (up to 2^21 samples per channel, or 8MiB
of
data per channel).

I currently have a thread-safe *cue spock brow* way of re-allocating the
buffers while the scope is running but it is not as clean as using a
mutex
(although it is faster, I'm sure). Here's how my method works.  Tell me
if
you think it is flawed or a hack-job...

Two booleans (private member vars of the gr_oscope_guts class) control
the
synchronization of the threads:
  bool        _update_record_count_internal;
  bool        _update_record_count_state_internal;

Thread A (the GUI), inverts the boolean _update_record_count_internal to
signal the other thread to perform an action (via the
set_samples_per_output_record function)

Thread B (the data flow), compares the two booleans inside the
process_sample function and takes action if they are inequal. It inverts
its
boolean after performing the operation.

------SNIP --- Added this function to the gr_oscope_guts class------
bool gr_oscope_guts::set_samples_per_output_record(int record_size)
{
  int tmp_record_size = record_size;
  //if record_size is out of bounds, fail
  if((record_size < MINIMUM_OUTPUT_RECORD_SIZE) || (record_size >
MAXIMUM_OUTPUT_RECORD_SIZE))
    return false;
  while(!(tmp_record_size&0x01)) // shift right until LSB is set, then
ensure the number is a power of 2
    tmp_record_size = tmp_record_size>>1;
  if(tmp_record_size^0x1) //see if any other bits are set. if so, it is
NOT
a power of 2
    return false;
    _new_record_count_internal = record_size;
    _update_record_count_internal = !_update_record_count_internal; //do
the
actual re-allocation inside the process_sample function
}
------------------------------------------------------------------------------


----SNIP from beginning of gr_oscope_guts::process_sample(const
float*)-----
  if(_update_record_count_state_internal !=
_update_record_count_internal)
  {
    set_samples_per_output_record_internal(_new_record_count_internal);
    _update_record_count_state_internal =
!_update_record_count_state_internal;
  }
----------------------------------

The function _update_record_count_state_internal performs the actual
de/re-allocation of buffers.

By the way -- what is the most graceful way of handling a failed memory
allocation?

Thanks in advance,
Tom
745d8202ef5a58c1058d0e5395a78f9c?d=identicon&s=25 Eric Blossom (Guest)
on 2009-05-13 22:21
(Received via mailing list)
On Wed, May 13, 2009 at 03:33:41PM -0400, Tom Lutz wrote:
>
> Thread A (the GUI), inverts the boolean _update_record_count_internal to
> signal the other thread to perform an action (via the
> set_samples_per_output_record function)
>
> Thread B (the data flow), compares the two booleans inside the
> process_sample function and takes action if they are inequal. It inverts its
> boolean after performing the operation.

This might work on x86 machines, but isn't safe on machines
with weak memory ordering across processors (e.g., PPC, Itanium).
You'd need to introduce architecture specific memory barriers.

Can you put the mutex at a higher level (e.g., in the object that
has the gr_oscope_guts)?

Eric
121f303ed62e30b569097a3d16825a94?d=identicon&s=25 Tom Lutz (Guest)
on 2009-05-13 22:36
(Received via mailing list)
> This might work on x86 machines, but isn't safe on machines
> with weak memory ordering across processors (e.g., PPC, Itanium).
> You'd need to introduce architecture specific memory barriers.
>
> Can you put the mutex at a higher level (e.g., in the object that
> has the gr_oscope_guts)?
>
> Eric
>

Wow, I totally didn't think of this.  Yes, I can place the mutex
inside gr_oscope_f, outside of a 'for' loop that processes a block of
samples (hopefully a block greater than 1).

-Tom
This topic is locked and can not be replied to.