deadpickle has asked for the wisdom of the Perl Monks concerning the following question:

I want to exit this thread by calling:
 $die = 1; $thread_chat->join; Gtk2->main_quit; The problem is that the while loop will only read the exit condition if a line is read from the server making the while loop blocking. I'm looking for a way to pass $die to the while loop so that it will exit. (I would like to refrain from detaching it since this is important so that the user can send messages to the server).
sub chat{ $|++; my $parser = Parse::IRC->new( public => 1 ); my %dispatch = ( 'ping' => \&irc_ping, '001' => \&irc_001, 'public +' => \&irc_public, 'quit' => \&irc_quit, 'join' => \&irc_join, '353' +=> \&irc_353); while(1){ if ( $die == 1 ){ goto END }; if ( $chat_start == 1 ) { $post = 1; $sock = new IO::Socket::INET(PeerAddr => $irc, PeerPort => 6667, Proto => 'tcp') or die "Can't connect\n"; # Log on to the server. print $sock "NICK $nick\r\n"; print $sock "USER $login 8 * :CoCoNUE Member $nick\r\n"; # Keep reading lines from the server. #for (;;){ #print "in\n"; while (my $input = <$sock>) { #print "1\n"; $input =~ s/\r\n//g; my $hashref = $parser->parse( $input ); #print "2\n"; SWITCH: { #print "3\n"; my $type = lc $hashref->{command}; my @args; push @args, $hashref->{prefix} if $hashref->{p +refix}; push @args, @{ $hashref->{params} }; if ( defined $dispatch{$type} ) { #print "4\n"; $dispatch{$type}->(@args); last SWITCH; } print STDOUT join( ' ', "irc_$type:", @args ), + "\n"; #print "5\n"; } #print "6\n"; #print "die = $die\n"; if ( $die == 1 ){print "Ending\n"; goto END }; if($chat_start == 0){ last}; } #print "out\n"; #if ( $die == 1 ){print "Ending\n"; goto END }; #if($chat_start == 0){ last}; #} close $sock; }else { sleep 1 } } END: }

Replies are listed 'Best First'.
Re: Joining a Thread in w While loop
by pc88mxer (Vicar) on Mar 05, 2008 at 04:52 UTC
    Check out Thread::Cancel. Alternatively, use select to multiplex between checking for the $die flag and reading input. Thirdly, use Gtk's IO dispatcher instead of threads.

    Pseudo-code for the select solution:

    my $sel = new IO::Select; $sel->add($sock); while (1) { if ($sel->can_read(1)) { # 1 second timeout # do read, appending to buffer sysread($sock, $buf, 1024, length($buf)); # check for a complete line, process command, etc. } last if ($die); }

    Update: Why can't you detach the thread? You're not returning any values from it. If you need to you can have it signal its completion by setting a shared variable.

      The reason I didnt want to detach the thread is because this is for the IRC client that I had to recode using Parse::IRC. I cant print to the $sock in the main code line making the user unable to send a message to the server. If I could get the while loop to be non-blocking then I could send a signal that tells the thread to send a message to the server (which now that I think about seems primitive). I may try the  select option but I have 1 question: how do you check for a complete line?
        To check for a complete line just use a regex:
        if ($buf =~ s/(.*\n)//) { # line is in $1 my $line = $1; ...process $line here... }

        Note that the s operator conveniently removes the first complete line from $buf as well as returns whether there was a complete line found or not.

        btw, have you considered using the Net::IRC module? Have a look at this example: http://jk0.org/projects/perl-irc-bot/