#!/usr/bin/perl use warnings; use strict; use threads; use threads::shared; use enum qw(:THREAD_CMD_ NONE WAIT WORK DIE); use enum qw(:THREAD_STATE_ WAIT WORK); my %thread_data:shared; $thread_data{'state'} = THREAD_STATE_WAIT; $thread_data{'cmd'} = THREAD_CMD_NONE; $thread_data{'nb'} = 0; #create thread before any tk code is called my $thr = threads->create( \&worker ); use Tk; my $mw = MainWindow->new(); $mw->protocol('WM_DELETE_WINDOW' => sub { &clean_exit }); my $button_stop = $mw->Button(-text => 'Stop thread', -command => sub { $thread_data{'cmd'} = THREAD_CMD_WAIT; while( $thread_data{'state'} != THREAD_STATE_WAIT ) { select(undef, undef, undef, 0.1); } })->pack(); my $button_start = $mw->Button(-text => '(Re)Start thread', -command => sub { $thread_data{'cmd'} = THREAD_CMD_WORK; while( $thread_data{'state'} != THREAD_STATE_WORK ) { select(undef, undef, undef, 0.1); } })->pack(); my $entry = $mw->Entry(-textvariable => \$thread_data{'nb'}, -width => 10)->pack(); MainLoop; sub clean_exit { my @running_threads = threads->list; if (scalar(@running_threads) > 1) { print "ERROR: Too many threads are active. There should be only one thread!\n"; } elsif (scalar(@running_threads) == 1) { $thread_data{'cmd'} = THREAD_CMD_DIE; $thr->join; exit; } else { print "ERROR: There should be at least one thread started!\n"; } } # no Tk code in thread sub worker { my $i = 0; THREAD_STATE_WAIT: $thread_data{'state'} = THREAD_STATE_WAIT; while(1) { if( $thread_data{'cmd'} == THREAD_CMD_WORK ) { $thread_data{'cmd'} = THREAD_CMD_NONE; goto THREAD_STATE_WORK; } elsif( $thread_data{'cmd'} == THREAD_CMD_DIE ) { $thread_data{'cmd'} = THREAD_CMD_NONE; return; } elsif( $thread_data{'cmd'} == THREAD_CMD_WAIT ) { $thread_data{'cmd'} = THREAD_CMD_NONE; goto THREAD_STATE_WAIT; } else { # wait select(undef,undef,undef,0.1); } } THREAD_STATE_WORK: $thread_data{'state'} = THREAD_STATE_WORK; print "\n"; $i = $thread_data{'nb'}; while(1) { if( $thread_data{'cmd'} == THREAD_CMD_WORK ) { $thread_data{'cmd'} = THREAD_CMD_NONE; goto THREAD_STATE_WORK; } elsif( $thread_data{'cmd'} == THREAD_CMD_DIE ) { $thread_data{'cmd'} = THREAD_CMD_NONE; return; } elsif( $thread_data{'cmd'} == THREAD_CMD_WAIT ) { $thread_data{'cmd'} = THREAD_CMD_NONE; goto THREAD_STATE_WAIT; } else { # work print $i . " "; select(undef,undef,undef,0.5); $i++; } } }