Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

threads, file handles and wxPerl

by sdetweil (Sexton)
on Feb 13, 2013 at 16:10 UTC ( #1018567=perlquestion: print w/replies, xml ) Need Help??
sdetweil has asked for the wisdom of the Perl Monks concerning the following question:

In my wxPerl based application, I need to launch and communicate (both its output and its input, stdin) with a shell scripted application (I also wrote).

in the event handler for the start button, we spin off a thread threads->create(\&routine), and it handles all the work.

uses open3 to start the child process, and reads its output (stdout & err) handles to get the console output and put it in a wxPerl textcontrol in a while(<HIS_OUT>) loop.

all works great.. up to the point the child issues a read

now I need to put up a dialog box to get content from the user and then write the response back to the child process.

per the Wx::Thread doc on CPAN I have setup a EVT_COMMAND event handler.
Wx::Event::EVT_COMMAND($panel, -1, $ID_OUR_EVENT, \&ourHandler +) sub ourHandler { my( $frame, $event ) = @_; my $text = $event->GetData; my $textvalue = Wx::GetTextFromUser($text, "some header", wxOK | w +xCANCEL,$self ) ; #---> what to do here with the dialog text. }

and when the data is detected in the subthread

I use
share (my $clientline); # in the main code, referenced here for clari +ty. my $event = new Wx::PlThreadEvent( -1, $ID_OUR_EVENT, $clien +tline); Wx::PostEvent($panel, $event );

to send the event message which causes my handler to fire. all works great. I put up the dialog, get the text from the user..

now I need to write back to the clients stdin ... but it was created in the thread subroutine. like this

local (*HIS_IN ,*HIS_OUT, *HIS_ERR, $childpid); use IPC::Open3; $childpid=open3( *HIS_IN, *HIS_OUT, *HIS_OUT,$command);

and I can write to it successfully in the thread
print HIS_IN $clientline . "\n";

however, I haven't found any way to get the handle from the thread to the main window loop. seems globs are not shareable.

anyone have any ideas?

when I try to use $panel->ProcessEvent() my application crashes with no feedback as soon as the dialog window is started. unlikely it is a stack size problem as the default is 16MB on Windows

on linux the dialog window appears, but then we crash, regardless of ok or cancel. and this is written to the console /usr/libexec/ No such file or directory.


late breaking update after successfully resolving all my issues, seeking something else wxPerl related, I came across Wx::Perl::ProcessStream, which completely replaces all the threading, open3(), file handle, and inter thread communication issues..

net reduction of complexity..

lines of output from the child process fire subroutines, methods provided to write back..

use Wx::Perl::ProcessStream qw( :everything ); # setup the stream handlers EVT_WXP_PROCESS_STREAM_STDOUT ( wxperl_window, \&evt_process_stdout +_err ); EVT_WXP_PROCESS_STREAM_STDERR ( wxperl_window, \&evt_process_stdout +_err ); EVT_WXP_PROCESS_STREAM_EXIT ( wxperl_window, \&evt_process_exit + ); EVT_WXP_PROCESS_STREAM_MAXLINES ( wxperl_window, \&evt_process_maxlin +es ); the handlers (here both the childs stdout & sterr are handled in the s +ame handler) sub evt_process_stdout_err { my( $self, $event ) = @_; $event->Skip(1); my $process = $event->GetProcess; my $clientline = $event->GetLine; $clientline=~s/"//g; $clientline=~s/\s+$//g; # string off all quotes and trailing whitespace # show it in the test window $detailsInfo->AppendText("$clientline\n"); # if the output line ends with identified line end, then it is abou +t to be a prompt if ($clientline=~m/($specialeol)$/) { my $textvalue = Wx::GetTextFromUser($clientline, "pre exit prom +pt", "",$self) ; $process->WriteProcess("$textvalue\n"); } } sub evt_process_exit { my ($self, $event) = @_; $event->Skip(1); my $process = $event->GetProcess; my $line = $event->GetLine; my @buffers = @{ $process->GetStdOutBuffer }; my @errors = @{ $process->GetStdErrBuffer }; my $exitcode = $process->GetExitCode; $process->Destroy; } the startup (this replaces all the thread goo) my $proc1 = Wx::Perl::ProcessStream::Process->new($command, 's +omelabel', wxperl_window)->Run;

Replies are listed 'Best First'.
Re: threads, file handles and wxPerl
by zentara (Archbishop) on Feb 13, 2013 at 16:24 UTC
      thanks.. using the fileno() gets me the results I need.. (if you clone the handle as input when u need to write to it!. well you get what you get!)
      this is the output approach
      open my $fh, ">&=$CHILD_FILENO";

        Be careful. The file won't close until you close both handles; but you have to ensure than you do not close the first handle before the the thread has had a chance to clone it. You may need a shared var as a semaphore to coordinate things.

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: threads, file handles and wxPerl
by bulk88 (Priest) on Feb 13, 2013 at 16:39 UTC
    Can you give me an entire working Wx Perl script I can run and see if it crashes?
      looks like this was not a wxPerl issue.. but a bad pointer somewhere in the file handle code. all my fault.
      altho unrelated, a wxPerl question Wx::GetTextFromUser() always has '20' in the dialog entry field
      how do you clear the entry field?

        That is probably the value of wxOK... (20), the third parameter in your code.

        Wx::GetTextFromUser( $message, $caption, $default_value, # $parent, # NULL # -1, # x = wxDefaultCoord # -1, # y = wxDefaultCoord # $centre, # true );
Re: threads, file handles and wxPerl
by zentara (Archbishop) on Feb 17, 2013 at 13:10 UTC
    Hi, as BrowserUk has pointed out, just using the fileno to pass filehandles can be frought with synchronization problems, which as he suggests can be controlled with the use of semaphores. But there is another way, which I wanted to suggest to you just as an idea.

    You could make a set of pipes to the thread, and this has the advantage that you can create the pipe in the main thread, and pass the pipe filehandle into the thread at creation time. The advantage to this is that as soon as you create the writer end of the pipe in the thread, you can immediately start writing the output of your thread's IPC3 output into the thread, without dealing with semaphores. See Using Select and pipes to communicate with threads for a simple example. You can probably use Wx's ProcessStream to watch the pipe's input, as I imagine it is like Tk's fileevent.

    Just a late thought I wanted to pass on to you. :-)

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1018567]
Approved by Corion
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (6)
As of 2018-11-14 07:27 GMT
Find Nodes?
    Voting Booth?
    My code is most likely broken because:

    Results (164 votes). Check out past polls.