Re: Threads sharing global variable
by BrowserUk (Patriarch) on Mar 02, 2016 at 12:52 UTC
|
There's no need to lock the queue handle; and you need to broadcast on both branches otherwise you've a race condition that is responsible for your hangs; and the sleeps are not useful.
Try this:
use threads;
use threads::shared;
use Thread::Queue;
my $a :shared = 0;
my $q = Thread::Queue->new();
sub set_positive {
while (1) {
lock $a;
if ($a == 0) {
$a = 1+int(rand() * 100); ## Modified 10/03/2016 15:57 in
+accordance with 1156654 & 1157305
$q->enqueue($a);
print "At set_positive: $a\n";
} else {
cond_wait($a)
}
cond_broadcast($a);
}
}
sub set_zero {
while (1) {
lock $a;
if ($a > 0) {
$a = 0;
$q->enqueue($a);
print "At set_zero: $a\n";
} else {
cond_wait($a)
}
cond_broadcast($a);
}
}
sub printer {
while (1) {
my ($v_a, $v_b) = $q->dequeue(2);
print "At printer $v_a $v_b ",$a, $/;
}
}
my @threads = map threads->create($_), qw( set_positive set_zero print
+er);
$_->join for @threads;
Outputs: C:\test>1156640
At set_positive: 11
At set_zero: 0
At set_positive: 98
At set_zero: 0
At set_positive: 2
At set_zero: 0
At printer 11 0 0
At printer 98 0 94
At printer 2 0 94
At set_positive: 94
At set_zero: 0
At set_positive: 61
At printer 94 0 0
At set_zero: 0
At printer 61 0 0
At set_positive: 13
At set_zero: 0
At printer 13 0 0
At set_positive: 13
At set_zero: 0
At printer 13 0 0
At set_positive: 28
At set_zero: 0
At printer 28 0 0
At set_positive: 18
At set_zero: 0
At printer 18 0 0
At set_positive: 59
At set_zero: 0
At printer 59 0 0
At set_positive: 15
At set_zero: 0
At printer 15 0 0
At set_positive: 31
At set_zero: 0
At set_positive: 22
At printer 31 0 0
At printer 22 0 0
At set_zero: 0
At set_positive: 19
At set_zero: 0
At printer 19 0 0
At set_positive: 2
At set_zero: 0
At printer 2 0 0
At set_positive: 22
At set_zero: 0
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] [select] |
|
use threads;
use threads::shared;
use Thread::Queue;
my $a :shared = 0;
my $q = Thread::Queue->new();
sub set_positive {
lock $a;
while (1) {
cond_wait($a) while $a > 0;
$a = int(rand() * 100) + 1;
cond_signal($a);
$q->enqueue($a);
}
}
sub set_zero {
lock $a;
while (1) {
cond_wait($a) while $a == 0;
$a = 0;
cond_signal($a);
$q->enqueue($a);
}
}
sub printer {
while (1) {
my ($v_a, $v_b) = $q->dequeue(2);
print "At printer $v_a $v_b\n";
}
}
threads->create($_) for qw( set_positive set_zero printer);
$_->join for threads->list;
cond_wait should always be used as cond_wait($lock) while !desired_condition();.
cond_signal (or cond_broadcast) is used when you change something checked by a thread's desired_condition().
Remember, your lock is released when you call cond_wait, and re-obtained before cond_wait returns.
| [reply] [d/l] [select] |
|
What do you get when you run this program ikegami?
I get one single line of output, i other words, it doesn't work
Like BrowserUk says, you lock the variable in the outer scope, and that lock is never released -- not an improvement
| [reply] |
|
|
|
|
|
|
|
|
Lots of unnecessary locking and unlocking,
And your version is sh*te! (Hint:locks should be held for as small a scope and for as little time as possible!). It may work for this specific do nothing, trivial example, but is entirely useless as a generic model of usage
Threads that lock all their shared variables when they start and never release them. What a great idea. I wonder why nobody's thought of doing that before(*).
And, as you you know, I'm not interested in your opinion (on anything), so feel free to feed your BS to the OP if you must, but stop polluting my day.
*Oh right. Because it only makes sense in a lock-stepped latching scenario, and besides that real examples of the need for that are as rare a rocking horse droppings; it is a completely stupid way to use threads.
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] |
|
|
Re: Threads sharing global variable
by Anonymous Monk on Mar 02, 2016 at 13:36 UTC
|
Note also that the expression int(rand() * 100) generates a number in the range 0..99 (inclusive). For non-zero value, you'll want to add one:
$a = 1 + int rand 100;
| [reply] [d/l] [select] |
Re: Threads sharing global variable
by Anonymous Monk on Mar 10, 2016 at 23:19 UTC
|
Regarding the motivation of this exercise. Although I am not the original poster, I see there's a need to provide some further background.
The readers-writers problem is an elementary problem in concurrency, and the typical solution involves the use of condition variables. The construct has its origins in 1974/1975 when Hoarse and Hansen formulated the idea of monitors.
The Art of Multiprocessor Programming introduces this problem in Chapter 1. Their example has Alice and Bob place sentences on a billboard one letter at a time.
"Both the mutual exclusion and producer-consumer protocols require waiting: if one participant is subjected to an unexpected delay, so is the other. ... Surprisingly, the readers-writers problem does have solutions that do not require waiting.
The scope of this exercise is no doubt to provide a working demonstration based on the method of condition variables. Again, the wikipedia article should prove informative.
| [reply] |
|
The readers-writers problem is an elementary problem in concurrency, and the typical solution involves the use of condition variables. The construct has its origins in 1974/1975 when Hoarse and Hansen formulated the idea of monitors.
Quoting ancient history serves no one any good. The world has move on -- a lot -- in the four decades since 1974/5. Especially with respect to concurrency and shared data.
"Both the mutual exclusion and producer-consumer protocols require waiting:
Read. Learn. Enjoy. Wait free algorithms.
Some choice quotes:
Wait-freedom is the strongest non-blocking guarantee of progress, combining guaranteed system-wide throughput with starvation-freedom. An algorithm is wait-free if every operation has a bound on the number of steps the algorithm will take before the operation completes.12 This property is critical for real-time systems and is always nice to have as long as the performance cost is not too high.
Wait-free algorithms were rare until 2011, both in research and in practice. However, in 2011 Kogan and Petrank15 presented a wait-free queue building on the CAS primitive, generally available on common hardware. Their construction expanded the lock-free queue of Michael and Scott,16 which is an efficient queue often used in practice. A follow-up paper by Kogan and Petrank17 provided a methodology for making wait-free algorithms fast and used this methodology to make the wait-free queue practically as fast as its lock-free counterpart. A subsequent paper by Timnat and Petrank18 provided an automatic mechanism for generating wait-free data structures from lock-free ones. Thus, wait-free implementations are now available for many data-structures.
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] |
|
| [reply] |