Convert this basic semaphore routine from perl to rust


#1

Hello,

I have the following code in Perl which dispatches several (8) threads at a time, and joins them right after they are done. The reason for doing things this way is that resources are freed as soon as they are no longer needed. This is better than joining all the threads at the very end.

Although I have found the Semaphore crate, I am having trouble figuring out a simple way to do the same thing in rust. From what I gather, it is not possible to check for whether a thread has joined without halting.

I realize that posting code in another language may be bad form, but I think the idea comes across rather straighforwardly.

Thanks.


#!/usr/bin/perl -w
use strict;
use threads;
use Thread::Semaphore;

my $max_threads = 8;
my $n = 100;
my $sem = Thread::Semaphore->new($max_threads);

for my $m (0 … $n) {
$sem->down;
my $t = threads->create(&some_function, m); # this mops up threads that are done _->join() for threads->list(threads::joinable);
}

# this mops up all the remaining threads
$_->join() for threads->list();

### Sub routines

sub some_function {
my $m = shift;
print “$m\n”;
# simulate a time-consuming task
sleep(1);
$sem->up;
}


#2

The reason for doing things this way is that resources are freed as soon as they are no longer needed. This is better than joining all the threads at the very end.

This may be true for Perl (but I strongly doubt that because it would be actually harder to implement!) but in Rust thread’s innards are deallocated at the point that the closure returns, not at the point that the thread gets joined.

If you strongly need to figure the list of joinable threads out, Rust standard library itself does not support a list of joinable threads (I guess there is no portable way to list them?), but you can always signal the joinability via any Sendable channel—for example you can have a multi-producer single-consumer queue to queue the finished thread (uniquely identified by a main thread’s index to the handle), and the main thread simply drop the handle to.

But… why should we do that when what we really want is to run N jobs in M predetermined threads (and M << N)? :smiley: There are numerous thread pool crates that exactly do what given Perl code does. They exactly implement aforementioned strategies and some more goodies (for example, “scoped pools” can access the outside of closure provided that the pool terminates at that scope).


#3

Wouldn’t std::sync::Barrier work for you here?


#4

Thank you, I’ll take a look at thread pools and barriers.


#5

I was able to get the code multi-threaded using the threadpool crate, with a channel, more or less as the example shows. Thanks again.