I''m trying to implement a baton passing mechanism using threads::shared, and either I am misunderstanding the semantics of the locking and signalling primitives or it would not seem possible to reliably implement this using them.

The mechanism is analogous to the passing of the baton in a relay race. There is a single shared scalar, and each thread blocks on that scalar until it signalled and contains that threads id.

The identified thread then has the baton, and does whatever it does until it sets the id of some other thread into the baton variable, signals it, and then goes back to waiting.

This is how I think it should be coded.

use strict; use warnings; use Time::HiRes 'sleep'; use threads; use threads::shared; my $baton:shared = 0; sub sprinter { my ($no_of_threads,$sleep) = @_; my $id = threads->self->tid; warn ("Thread $id started\n"); while (1) { lock ($baton); cond_wait ($baton) until $baton == $id; warn ("Thread $id has the baton\n"); sleep ($sleep); $baton = int (rand ($no_of_threads)) until $baton != $id; warn ("Thread $id passing the baton to thread $baton\n"); cond_signal ($baton); # cond_broadcast ($baton); } } my ($no_of_sprinters, $sleep ) = @ARGV; $no_of_sprinters ||= 3; my @threads; push @threads,threads->new (\&sprinter,$no_of_sprinters, $sleep) for 1..$no_of_sprinters; sleep 1; while(1){ lock ($baton); cond_wait ($baton) until $baton == 0; warn ("Thread 0 has the baton\n"); sleep ($sleep); $baton = int (rand ($no_of_sprinters)) until $baton != 0; warn ("Thread 0 passing the baton to thread $baton\n"); cond_signal ($baton); # cond_broadcast ($baton); }

If you run this a few times, it will sometimes never pass the baton. Sometimes pass it few times and then hang.

It never seems to pass the baton more that the number of threads specified, though it will sometimes successfully pass it to the same thread two or more times before stopping.

I have found what appears to be a reliable cure (with a caveat). If you switch from using cond_signal to cond_broadcast, with no other changes it seems to run reliably for as long as you choose to leave it.

The question is, why is it necessary to use cond_broadcast? Or, what changes are required to make the cond_signal version work?

The caveat I mentioned is that whilst you can reduce the sleep value to 0.0, if you comment out the sleeps entirely, even the cond_broadcast version hangs almost at once?

This may be something to do with the note in the pod that says <cite> If there are no threads blocked in a cond_wait on the variable, the signal is discarded. By always locking before signaling, you can (with care), avoid signaling before another thread has entered cond_wait(). </cite>

I am always locking before signalling, so what extra "care" do I need to take?


In reply to baton passing threads and cond_signal by Anonymous Monk

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.