I was playing with this code, from the way the beep is sounding, once the program starts it doesn't stop. I suspect the problem is with $thread->kill('KILL')->detach;.
Any ideas? Or have I done something wrong ?
#!c:/perl/bin/perl
use threads;
use Audio::Beep;
my $thread;
my $playing=0;
while (1) {
my $val = int( rand(10) );
print "$val\n";
# if event "start" occurs and is not playing create thread
#if ( ($val==0 || $val==1 || $val==2 || $val==3 || $val==4 ) && (!$playing) ) {
if ( ($val==0 || $val==1 || $val==2 ) && (!$playing) ) {
$playing = 1;
$thread = threads->create(
sub {
local $SIG{'KILL'} = sub { threads->exit() };
print "start beep\n";
beep( 520, 10000 );
}
);
}
# if event "end" occurs and playing wait 1 seconf and kill thread
elsif ( ($val==5 ) && $playing ) {
print "stop beep \n";
#sleep(1);
$playing = 0;
$thread->kill('KILL')->detach;
}
#sleep(1);
$count = 0;
for($i=0; $i<99999 ; $i++) {
$count++;
}
}
I think your program is mostly working as you intend. One of the problems with what I see now is that every beep sounds alike. I re-wrote it a little to give the beep some texture, and to slow things down so that you can appreciate what's happening.
Also, as you've written it, there's a possibility that the thread will end on its own, before you can kill it. I've made the thread persistent, and added additional diagnostic information which will confirm when the thread is running and when it is not.
use strict;
use warnings;
use threads;
use Audio::Beep;
my $thread;
my $playing=0;
while (1) {
my $val = int( rand(30) );
print "$val\n";
my $running = threads->list(threads::running);
print "Threads running: $running\n";
# if event "start" occurs and is not playing create thread
if ( ( $val==1 ) && (!$playing) ) {
$playing = 1;
print ">>>>>>>>\n";
sleep(1);
$thread = threads->create(
sub {
local $SIG{'KILL'} = sub { threads->exit() };
print "start beep\n";
while (1) {
beep( 520, 100 );
sleep(1);
beep( 3800, 100 );
sleep(1);
beep( 2000, 100);
sleep(1);
}
}
);
}
# if event "end" occurs and playing wait 5 seconds and kill thread
elsif ( ($val==2 ) && $playing ) {
print "STOPSTOPSSTOPSTOPSTOP\n";
sleep(5);
$thread->kill('KILL')->detach;
$playing = 0;
}
for(my $i=0; $i<999999 ; $i++) {}
}
Related
The following is a simple code example I'm working on. It just starts a thread, wait 5 seconds, and then terminate it.
#!/usr/bin/perl
use strict;
use warnings;
use threads;
sub thread_sub
{
threads->create(sub
{
sleep 5; # HERE A WHILE ROUTINEs EMULATED BY SLEEP
threads->detach();
});
}
thread_sub();
exit;
But the result is:
# ./multithread.pl
Perl exited with active threads:
1 running and unjoined
0 finished and unjoined
0 running and detached
This because it runs the thread but after that exit without waiting.
So, how can I wait for thread to finish before exit? I know there is is_running, but I don't known how to implement it in my code. Obliviously the reported code is just an example to understand how to implement is_running. Thank you.
To wait for a thread to finish, one typically uses the following:
$thread->join();
To wait for all threads, one would therefore use the following:
$_->join() for threads->list();
Don't detach the thread if this is what you are going to do.
About detach...
If you had fire-and-forget threads, you could use
use threads;
use threads::shared;
my $thread_count :shared = 0;
sub thread_sub {
{ lock $thread_count; ++$thread_count; cond_signal($thread_count); }
my $thread = async {
sleep 5;
{ lock $thread_count; --$thread_count; cond_signal($thread_count); }
};
$thread->detach(); # Free the small thread object as soon as it completes.
}
thread_sub();
# When it's time to exit:
{ lock($thread_count); cond_wait($thread_count) while $thread_count != 0; }
But that doesn't gain you much over just joining the threads, which is far simpler.
use threads;
sub thread_sub {
async {
sleep 5;
};
}
thread_sub();
# Periodically:
$_->join() for threads->list(threads::joinable);
# When it's time to exit:
$_->join() for threads->list();
Finally, it's more common in practice to create a pool of threads and reuse them rather then creating threads on the fly because thread creation is expensive in Perl. In this situation, detaching makes even less sense.
use threads;
use Thread::Queue qw( ); # 3.01+
use constant NUM_WORKERS => 3;
sub process_job { sleep 5 }
my $q = Thread::Queue->new();
for (1..NUM_WORKERS) {
async {
while (my $job = $q->dequeue()) {
process_job($job);
}
};
}
$q->enqueue('some_job');
# When it's time to exit:
$q->end();
$_->join() for threads->list();
I haven't used it, but look into Thread::Pool.
By the way, async { ... } is just a cleaner way of saying threads->create(sub { ... }).
Why are you doing this? Detaching a thread means that you don't care about its return or fate; it will finish and exit or be killed as the program is about to exit.
If you want to wait for it don't detach but join.
As for the question of how to use is_running, you need a thread object
use warnings;
use strict;
use feature 'say';
use threads;
$| = 1;
sub thread_sub
{
my $thr = threads->create(sub
{
## threads->detach();
sleep 2; say "\tprocessing ..";
sleep 2; say "\tdone";
});
return $thr;
}
my $thr = thread_sub();
while ($thr->is_running) { # or: while (threads->list)
sleep 1;
say "main";
}
$_->join for threads->list; # instead of detaching
say "done";
Btw, a detached thread is also covered by is_running (or list) and the above works for it as well. But doing that doesn't make sense; I am just discussing the method you ask about.
The sound output functions are giving me unexpected messages. Is this a sign I'm doing something wrong? If so what? Otherwise is there a good source that explains what these messages might be?
waveOutOpen() gives me message 955 MM_WOM_OPEN as documented, followed by an undocumented 1024 (possibly DDM_SETFMT, DM_GETDEFID, NIN_SELECT, TBM_GETPOS, WM_PSD_PAGESETUPDLG, WM_USER, according to https://wiki.winehq.org/List_Of_Windows_Messages).
In main thread:
hAudioOut = CreateThread( 0, 0, AudioOutThreadProc, this, 0, &dwAudioOutId );
if( !hAudioOut ) {
AKS( AKSWarn, "Audio Out CreateThread() fail" );
return;
}
In the resulting audio thread:
static DWORD WINAPI AudioOutThreadProc( LPVOID lpParameter ) {
Interpreter* pinterp = (Interpreter *) lpParameter;
WAVEFORMATEX waveFormat;
waveFormat.cbSize = sizeof(waveFormat);
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
waveFormat.nChannels = 1;
waveFormat.nSamplesPerSec = (int) dFreqEval;
waveFormat.wBitsPerSample = iOutputBits;
waveFormat.nBlockAlign = waveFormat.nChannels *
waveFormat.wBitsPerSample / 8;
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec *
waveFormat.nBlockAlign;
MMRESULT openRes = waveOutOpen( &waveOut, WAVE_MAPPER, &waveFormat,
(DWORD_PTR) dwAudioOutId, (DWORD_PTR) this,
CALLBACK_THREAD /*| WAVE_FORMAT_DIRECT*/ );
if ( openRes != MMSYSERR_NOERROR )
Log( "waveOutOpen() = %d", openRes );
MSG msg;
int iRV;
while ( iRV = GetMessage( &msg, 0, 0, 0 ) ) {
Log( "got message %d", msg.message );
// Is the main thread asking us to stop?
if ( pinterp->bStop ) {
Log( "AudioInThreadProc(): bStop" );
return EXIT_SUCCESS;
}
// Did we get an error?
if ( iRV == -1 ) {
Log( "GetMessage() = -1: %d", GetLastError() );
abort();
}
// Did we get an expected message? (Only one expected,
// which tells us its time to write more data.)
if ( msg.message == WOM_DONE )
pinterp->Write();
// Anything else--log it.
else
Log( "got unknown message %d", msg.message );
}
Log( "AudioInThreadProc(): GetMessage = return" );
return msg.wParam;
}
waveOutWrite() isn't documented to give any messages, but is giving me message 1024 as well.
sub worker {
exit 1;
}
my $thr = threads->create(\&worker);
while ($thr->is_running()) {
print "running\n";
}
my $rc = $thr->join();
exit $rc;
I come from Python. Is there something similar to try/except that I can use around while($thr->is_running)
I get (because I exit 1 in worker):
Perl exited with active threads:
0 running and unjoined
1 finished and unjoined
0 running and detached
I want to be able to catch the exit or other compiliation error worker might have
use strict;
use warnings;
use threads;
sub worker {
my $bad = 1/0;
}
my $thr = threads->create( \&worker );
while ( $thr->is_running() ) {
sleep 1;
}
my $rc = $thr->join(); #NB - RC will be 'undef' because there's no return.
OUTPUT:
Thread 1 terminated abnormally: Illegal division by zero at mythread.pl line 6.
Is it possible to catch it the error? and how and where?
Don't call exit in your thread. That exits your whole program. threads -> exit is what you want.
http://perldoc.perl.org/threads.html#EXITING-A-THREAD
threads->exit()
If needed, a thread can be exited at any time by calling threads->exit() . This will cause the thread to return undef in a scalar context, or the empty list in a list context.
When called from the main thread, this behaves the same as exit(0).
join waits for the thread to complete.
Don't use $a. It's a bad variable name anyway, but it's also used for perl sort.
You're capturing $rc but that implies a return in your thread. As it, it'll be undefined.
But this will work:
use strict;
use warnings;
use threads;
sub worker {
sleep 10;
threads->exit;
}
my $thr = threads->create( \&worker );
while ( $thr->is_running() ) {
print $thr ->tid, " running\n";
sleep 1;
}
print $thr ->tid, " not running\n";
sleep 5;
my $rc = $thr->join(); #NB - RC will be 'undef' because there's no return.
In the latter case, $rc is undef because you exited. You can test for it being undefined if you want to trap an abnormal exit. (Just make sure you do actually return something on a success).
Alternatively, wrap your code in the thread with an eval because that won't be a fatal error. Doesn't come up too often, but I'd suggest rather than trying to capture the broad spectrum of possible fatal errors, you're far better off just testing whether it completed successfully instead.
To answer your second question - something like this:
use strict;
use warnings;
use threads;
sub worker {
sleep 5;
my $fatal = 1 / 0;
return 1;
}
sub otherworker {
sleep 4;
eval { my $fatal = 1 / 0; };
if ($#) { return $# }
else { return "No error" }
}
my $thr = threads->create( \&worker );
my $thr2 = threads->create( \&otherworker );
while ( $thr->is_running() ) {
print $thr ->tid, " running\n";
sleep 1;
}
print $thr ->tid, " not running\n";
foreach my $thread ( threads->list ) {
my $return_code = $thread->join;
if ( not defined $return_code ) {
print $thread ->tid(), ": terminated abnormally\n";
}
else {
print $thread ->tid, ": exited with $return_code \n";
}
}
I am creating a pty using openpty in C, and sharing it between master/parent and slave/child. The child could fork/exec and pass on the file descriptor to other programs. I want to inject commands to the child, but if I pass them immediately they get lost. How can I tell from the parent process that someone is blocking on input from stdin? I happen to be working on SUSE 10, but I would prefer a distro independent solution.
Edit : The answer to this question is still interesting to me, but may not be relevant to the problem. I'll get to that later.
A simplified version of the code would be to use the script source code (some of the headers may need to be fixed), and add the lines
char* command = "echo 'Hello World!'\r\n", written = 0;
(void)write(master, command, strlen(command));
(void)write(STDOUT_FILENO, "Sent command\r\n", 14);
before the big
for (;;) {
in main.
I had been executing a csh from script, but I then noticed that the script command was dumping some garbage (as viewed in vi)
^[[>0;115;0c
onto the parent's stdin. If I instead exec a bash shell, nothing gets dumped out and the program injects the command just fine.
I'm still curious as to the answer to the question being asked, but it is clearly no longer relevant to my problem, as there is something else going on. If anyone does know how to see if a pty is being read feel free to answer.
As far as I know, file descriptors will not survive a trip to another process. You can share them between threads, though.
As for knowing when there is something to read, I'd try using select with the appropriate file descriptor in the read set.
I have noticed same problem about losting stuff when I write to master fd.
Problem can be avoided by using the slave fd for writing. And the master fd for stdin of child.
This way:
int main(void)
{
int master_fd = -1;
int slave_fd = -1;
if( openpty( &master_fd, &slave_fd, NULL, NULL, NULL ) != -1 )
{
const pid_t child_pid = fork();
if( child_pid != -1 )
{
if( child_pid )
{
const char command[] = "command\n";
close( master_fd );
write( slave_fd, command, strlen(command) );
close( slave_fd );
}
else
{
close( slave_fd );
dup2( master_fd, STDIN_FILENO );
execlp( "/bin/cat", "cat", (char*)0 );
}
}
}
return 0;
}
You may even add delays to child process and it still works.
So parent process can exit before the child process do anything:
~ # temp_test
~ # command
cat: read error: Input/output error
~ #
EDIT:
Little bit different example, because error print out of cat causes confusing:
if( child_pid )
{
const char command[] = "command\n";
close( master_fd );
write( slave_fd, command, sizeof(command) );
close( slave_fd );
}
else
{
char buffer[100];
ssize_t i;
ssize_t len;
close( slave_fd );
do
{
len = read( master_fd, buffer, sizeof(buffer) );
for( i = 0; i < len; i++ )
printf("%c", buffer[i] );
} while( len > 0 );
}
And result:
~ # temp_test
command
~ #
Hi i am trying to use microsofts visual studio 2010 to make a text based game the only problem is when i made some functions it gave me this error when i wanted to run it error C2143: syntax error : missing ';' before 'constant' i can't figure it out. here is the script this is in c++
// Text Game.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdlib.h>
void ShowIntroduction ( void )
{
printf( "Hello welcome to this text-based adventure game.\n" );
printf( "In this adventure game we will run into many difficult situations\n" );
printf( "1. A situation will present it's self\n" );
printf( "2. You will be given some choices.\n" );
printf( "3. You will need to make some choices.\n" );
printf( "4. The result of your choice will be shown.\n" );
}
void ShowSituation1 ( void )
{
printf( "\n\nYou are walking down a loney, dusty road.\n" );
printf( "When you see a gem on the ground.\n" );
printf( "It is bright and shiny!!\n" );
}
void ShowSituation2 ( void )
{
printf( "\n\nThe cave entrance looks inviting.\n" );
printf( "You are tempted to enter.\n" );
printf( "It looks kind of dark.\n" );
}
void ShowSituation3 ( void )
{
printf( "\nDo you want to keep going?\n" );
}
void ShowChoices1 ( void )
{
printf( "\nHere are your choices\n" );
printf( "1. Pick up the gem.\n");
printf( "2. Kick the gem off the road.\n" );
printf( "3. Stomp on the gem.\n" );
}
void ShowChoices2 ( void )
{
printf( "\nHere are your choices.\n" );
printf( "1. Run away\n" );
printf( "2. Take a nap.\n" );
printf( "3. Slowly enter the cave.\n" );
}
void ShowChoices3 ( void )
{
printf( "\n1. Ya I ain't scared.\n" );
printf( "2. No I need my mommy.\n" );
}
int GetChoice ( int min, int max)
{
int Choice;
do
{
printf( "Your choice? " );
scanf( "%d", &Choice );
}
while( Choice < min || Choice > max );
return( Choice );
}
void ShowResults1 ( int Choice )
{
if( Choice == 1 )
{
printf( "\nYou pick up the gem and put it in your backpack.\n" );
printf( "You start walking down the road when you see smoke coming from your backpack.\n" );
printf( "Quickly you throw your bag off and jump down the hill just in time to escape the explosin from your bag.\n" );
printf( "You continue to roll down the hill, when you finally stop you get up and find a cave.\n" );
}
else if( Choice == 2 )
{
printf( "\nThe gem flys off the road.\n" );
printf( "You decide to see if you can find where it landed.\n" );
printf( "When you reach the bottom you notice a cave.\n" );
}
else if( Choice == 3 )
{
printf( "\nThe gem sends you sky high.\n" );
printf( "You hope that your health insurance is up to date.\n" );
printf( "Lucky for you it was a nice grassy hill you landed on.\n" );
printf( "You stand up to figure out where you are.\n" );
printf( "You notice a cave.\n" );
}
else
{
printf( "\nThat wasn't a Choice you bozo.\n" );
printf( "You are dead now!!\n" );
exit (0);
}
}
void ShowResults2 ( int Choice )
{
if( Choice == 1 )
{
printf( "\nWhat a chicken.\n" );
printf( "Looks like you need your mommy.\n" );
exit 0;
}
else if( Choice == 2 )
{
printf( "\nIt is night time when you awake.\n" );
printf( "You get up and start walking but don't make it far.\n" );
printf( "You were attacked by a pack of wolves.\n" );
exit 0;
}
else if( Choice == 3 )
{
printf( "You enter the cave slowly.\n" );
printf( "Your only light sorce is a lighter in your pocket.\n" );
printf( "You find a torch on the wall, you get the torch lit.\n" );
}
else
{
printf( "\nThat wasn't a Choice you bozo.\n" );
printf( "You are dead now!!\n" );
exit (0);
}
}
void ShowResults3 ( int Choice )
{
if( Choice == 1 )
{
printf( "\nYou decide to keep going.\n" );
}
else if( Choice == 2 )
{
printf( "\nWhat a pussy you are!!\n" );
exit 0;
}
else
{
printf( "\nThat wasn't a Choice you bozo.\n" );
printf( "You are dead now!!\n" );
exit (0);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int Choice;
ShowIntroduction ();
ShowSituation1 ();
ShowChoices1 ();
Choice = GetChoice ( 1,3 );
ShowResults1 ( Choice );
ShowSituation2 ();
ShowChoices2 ();
Choice = GetChoice ( 1,3 );
ShowResults2 ( Choice );
ShowSituation3 ();
ShowChoices3 ();
Choice = GetChoice ( 1,3 );
ShowResults3 ( Choice );
return 0;
}
It's exit(0), not exit 0.
You could have narrowed this down really easily. Also please next time check the formatting of your post before you submit: there is a preview pane on the Ask Question page.