http://www.perlmonks.org?node_id=932801


in reply to Win32: Starting and stopping processes (part 1)

Thanks guys.

I took BrowserUK's suggestion to convert to threads instead of separate processes. It works well with a minimum of effort. supervisor.pl reads from 4 different sockets (the worker bees), so the Queues wouldn't work nearly as efficiently as the select call on the UDP sockets does.

I created a "system tray" application with Win32::GUI, and Win32::Daemon to create a windows service. The service presents a little icon in the system tray which, when clicked, opens a little window that has start and stop buttons. "Start" opens supervisor.pl and the four dwarves (now "require" subroutines) as new threads in the server process. "Stop" shuts them down in an orderly fashion.

"Stop" was still a problem, but was easily solved. Since supervisor and the dwarves send datagram messages back and forth constantly, I just created a new "message type" of "goodbye". Supervisor tells each dwarf "goodbye", and the dwarf shuts itself down.

To get the service "starter.pl" to tell supervisor to shut down, I had to create a new datagram socket on supervisor to listen for a "goodbye" message from starter. Easily done. This eliminates the Unix signals method.

Here's the code I used for "starter.pl". It's still preliminary, but it works, and it's almost starting to look like a professional application! Wow, you know, this Windows stuff might catch on one of these days...

#!/usr/bin/perl use threads; use strict; use Socket; use Fcntl; use Errno; use Time::HiRes qw ( time alarm sleep ); use Brewery; use PID; use SSR; my $thr1; my $thr2; my $thr3; my $thr4; my $thr5; use Win32::Daemon; # Tell the OS to start processing the service... Win32::Daemon::StartService(); # Wait until the service manager is ready for us to continue... while( SERVICE_START_PENDING != Win32::Daemon::State() ) { sleep( 1 ); } # Now let the service manager know that we are running... Win32::Daemon::State( SERVICE_RUNNING ); chdir("c:/Documents and Settings/Owner/Desktop/WWW/brewery/threads"); require "c:/Documents and Settings/Owner/Desktop/WWW/brewery/threads/s +upervisor.pl"; require "c:/Documents and Settings/Owner/Desktop/WWW/brewery/threads/c +trlman.pl"; require "c:/Documents and Settings/Owner/Desktop/WWW/brewery/threads/p +idman.pl"; require "c:/Documents and Settings/Owner/Desktop/WWW/brewery/threads/p +rogman.pl"; require "c:/Documents and Settings/Owner/Desktop/WWW/brewery/threads/w +ebman.pl"; use Win32::GUI(); # my $DOS = Win32::GUI::GetPerlWindow(); # Win32::GUI::Hide($DOS); my $main = Win32::GUI::Window->new( -name => 'Main', -text => 'Perl', -width => 220, -height => 100, -text => 'The Electronic Brewery' ); my $start_button = $main->AddButton( -name => 'Start', -text => 'Start', -pos => [ 60, 30 ] ); my $stop_button = $main->AddButton( -name => 'Stop', -text => 'Stop', -visible => 0, -pos => [ 100, 30 ] ); my $theLabel = $main->AddLabel( -text => 'The Brewery is: STOPPED', -pos => [40,0] ); my $icon = new Win32::GUI::Icon('c:/Documents and Settings/Owner/D +esktop/WWW/brewery/favicon.ico'); my $ni = $main->AddNotifyIcon( -name => "NI", -icon => $icon, -tip => "The Electronic Brewery" ); Win32::GUI::Dialog(); sub Main_Terminate { $main->Disable(); $main->Hide(); return 0; } sub Main_Minimize { $main->Disable(); $main->Hide(); return 1; } sub NI_Click { $main->Enable(); $main->Show(); return 1; } sub Start_Click { $theLabel->Text('The Brewery is RUNNING'); $start_button->Hide(); $stop_button->Show(); $thr1 = threads->create(\&supervisor); $thr2 = threads->create(\&ctrlman); $thr3 = threads->create(\&pidman); $thr4 = threads->create(\&progman); $thr5 = threads->create(\&webman); return 0; } sub Stop_Click { $theLabel->Text('The Brewery is STOPPED'); $start_button->Show(); $stop_button->Hide(); my $iaddr = inet_aton("127.0.0.1"); my $proto = getprotobyname("udp"); my $port = 0; my $paddr = sockaddr_in( $port, $iaddr ); socket( SUPERVISOR, PF_INET, SOCK_DGRAM, $proto ) || die "sock +et: $!"; bind( SUPERVISOR, $paddr ) || die "bind: $!"; $port = 5000; my $dest = sockaddr_in($port, $iaddr); send(SUPERVISOR, "goodbye", 0, $dest); return 0; }