in reply to Re: Global variables and SimpleHTTP request handler
in thread Global variables and SimpleHTTP request handler

Perhaps I should expand a little on what I'm trying to do. I tried to keep my original post down to the bare details.

For those who have not come across it, Scratch is a drag and drop programming language for kids. I'm trying to write an extension to it which can allow the control of Neopixels - programmable LEDs. The Scratch extension sends my custom command to a web server with all the parameters in a URL to a local web server. E.g. the scratch block tries to set pixel 2 with the RGB value 255,0,255 then the requested URL is:

/setneo/2/255/0/255

The hardware itself is being driven by an Arduino which I'm communicating with over a serial cable. Scratch can send the requests faster than the arduino can process them so I need my request handler to place them in a queue which will then be sequentially processed.

At the moment the queue processor is just the while loop at the end of the example I give, so it is in the same package. Currently it is just reporting on how big the queue is, but once it can see data from request_handler then it will expand to do something more useful.

If a global variable can not be used, then I could look at using a file as a processing queue, but that sounds messy. Is there any other way to share data between two forked processes? A future expansion might be for Scratch to wait until the Arduino has processed a command or accept an input from the Arduino, so eventually I might be looking at a two way communication between the two bits of code.

Replies are listed 'Best First'.
Re^3: Global variables and SimpleHTTP request handler
by Corion (Patriarch) on Jan 03, 2017 at 14:56 UTC

    For communication between processes, see perlipc.

    Maybe you can use non-blocking communication within a single process by using AnyEvent, but it's likely much easier to write the commands to a file or to simply not return a response from your webserver until the command has been processed, thus pushing the requirement for asynchronicity to Scratch.

    For some value of "easy", using threads can make it easy to have shared access to a common data structure which is modified concurrently. If your Perl has been compiled with thread support, that may give you a nicer approach. I still recommend a command queue approach using Thread::Queue.

      Thank you so much, Thread::Queue does exactly what I need, though the MCE suggestion looks like it would have also worked.

      There was a slight oddity that it did not work with SimpleHTTP backgrounded. I had to create my own thread for that and use run().

      use threads; use Thread::Queue; my $command_queue=Thread::Queue->new(); sub handle_request { my ($self, $cgi) = @_; my $cmd_out; ........ $command_queue->enqueue($cmd_out); my $commands_left=$command_queue->pending(); myDebug("Threads - there are $commands_left items in the queue"); } my $server_thread=threads->create( sub { # Run server but do not background it. myDebug("Starting web server\n"); my $pid = MyServer->new($PORT)->run(); } } while($quit==0) { my $commands_left=$command_queue->pending(); myDebug("Queue runner - There are $commands_left entries in the qu +eue"); if($commands_left>0) { print "We have commands to process\n"; $send_command=$command_queue->dequeue(); print "Sending: $send_command\n"; } # Sleep so we do not hog the processor sleep(1); }

      All seems to work nicely. :)

Re^3: Global variables and SimpleHTTP request handler
by 1nickt (Canon) on Jan 03, 2017 at 15:17 UTC

    You can share data between two processes spawned by any forker, or threads, using MCE::Shared. See many nodes here at the monastery by marioroy, author of MCE -- for example this demonstration.

    Here's an example of some code I use to push to a shared array from multiple workers that are also managed by MCE:

    use MCE::Loop; use MCE::Candy; my $shared = [ ]; MCE::Loop::init( max_workers => $CONFIG->max_workers_MCE, chunk_size => 100, gather => MCE::Candy::out_iter_array( $shared ), ); mce_loop { my ( $mce, $chunk_ref, $chunk_id ) = @_; my @items_to_gather; foreach my $item ( @{ $chunk_ref } ) { push @items_to_gather, $item; # your logic here } MCE->gather( $chunk_id, @items_to_gather ); } @list;

    Hope this helps!


    The way forward always starts with a minimal test.