Besides not bothering to format your post correctly, your question is so open to interpretation of your meaning that it is impossible to answer it properly, without you clarify what you are hoping to achieve?
I suspect that when you run it, you are seeing an effect like this:
Note: I've un-doubled the newlines for compactness.
c:\test>616053 THREAD: in da zone !! :) THREAD: in da zone !! :) the THREAD: in da zone !! :) quicTHREAD: in da zone !! :) k broTHREAD: in da zone !! :) wn fTHREAD: in da zone !! :) ox jTHREAD: in da zone !! :) umpsTHREAD: in da zone !! :) over THREAD: in da zone !! :) the lTHREAD: in da zone !! :) azTHREAD: in da zone !! :) y doTHREAD: in da zone !! :) gTHREAD: in da zone !! :) MAIN:the quick MAIN:brown fox MAIN:jumps over MAIN: the lazy THREAD: in da zone !! :) Terminating on signal SIGINT(2)
That is, the output from the thread is interfering with your attempts to type input making it difficult to type and impossible to edit.
Now one thing you can do is to serialise the use of the shared resource, the console, using a semaphore:
#! perl -sw use strict; use threads; use threads::shared; my $sem: shared; my $thr = threads->new(\&sub1); sub sub1 { while(1){ lock $sem; print "THREAD: in da zone !! :) \n"; sleep 1; }; } while(1){ lock$sem; my $stuff=''; read STDIN , $stuff,10; print "MAIN:", $stuff , "\n" ; }
And you'll see something like this:
c:\test>616053 the quick brown fox jumps over the lazy dog MAIN:the quick THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) MAIN:brown fox MAIN:jumps over MAIN: the lazy But I had to some more in order to see the end of the last input MAIN:dog But I MAIN:had to som MAIN:e more in MAIN:order to s MAIN:ee the end MAIN: of the la Terminating on signal SIGINT(2)
That will suspress output whilst you are typing which will make typing easier and editing possible. However, using read 10 will break up the input and cause it to be output in lumps of 10 characters and stop any less-than-10 characters residual at the end of the line from being displayed until you enter some more.
So I suspect that isn't the complete answer to your badly asked question either.
You can fix that problem by reading a line at a time. Insead of read, use readline or it's <STDIN> alias:
#! perl -sw use strict; use threads; use threads::shared; my $sem: shared; my $thr = threads->new(\&sub1); sub sub1 { while(1){ lock $sem; print "THREAD: in da zone !! :) \n"; sleep 1; }; } while(1){ lock$sem; my $stuff = <STDIN>; print "MAIN:", $stuff , "\n" ; }
Now your input is displayed in the same way you entered it:
c:\test>616053 the quick brown fox jumps over the lazy dog MAIN:the quick brown fox jumps over the lazy dog THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) enter some more MAIN:enter some more enter some more MAIN:enter some more Terminating on signal SIGINT(2)
But, the input loop re-acquires the lock on the semaphore so quickly after each input completes that you never see any output (after the first batch) from the thread. Though if you have a multi-cpu system you might.
To fix that, you need to relinquish the cpu, between reads. The addition of a sleep 1; to the read loop achieves that with this result:
c:\test>616053 the quick brown fox jumps over the lazy dog MAIN:the quick brown fox jumps over the lazy dog THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) and some more meaningless input here MAIN:and some more meaningless input here and some more meaningless input here MAIN:and some more meaningless input here THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) and more MAIN:and more and more MAIN:and more THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) THREAD: in da zone !! :) Terminating on signal SIGINT(2)
Which is closer, but still probably not what you are hoping to achieve, because it means you won't see what the thread produces whilst you are typing until you finished typing.
I suspect what you'd like, is for the output from the thread (but not what you are typing) to continue to scroll up the screen as you type. And for what you type to remain static at the bottom of the screen until you hit the enter key, whence it would be displayed amongst, and scroll with, the other output on the screen. Whilst leaving the prompt sitting waiting on the bottom of the screen for your next input.
Here's the rub. To do that, you will have to control the cursor. Traditionally under unix this is done using ansi escape sequences, usually via curses or ncurses or some similar library. Though I suspect that those libraries are probably not re-entrant (thread safe), and using them in conjuction with multiple threads would be difficult, if not impossible. In any case, the win32 console doesn't do ansi escape sequences. It has it's own very powerful library of cursor and console control facilities.
This is accessible via Win32::Console. The documentation for that module is sparse, relying mostly upon a link/reference to the MS documentation of the underlying APIs, but the MS website being what it is--every page/url getting changed/moved everytime someone in the management hierarchy gets promoted--the links are broken and relocating them (especially in the days before Google), seems to be quite hard. For reference, the current link is at Console Reference.
There is also the extremely useful Term::ANSIScreen which sits on top of Win32::Console and emulates a subset of ansi escape sequences allowing some level of portability for applications that use them. This is thread-safe. Unfortunately, it doesn't emulate the most useful ansi (actually vt102, but adopted by ANSI ANSI X3.41-1974) escape sequence for doing the sort of thing I suspect you are trying to achieve, namely the SetScrollRegion.
So where does all that leave you?
It is definitely possible to achieve a static input line(s) and have the rest of the screen scroll. This can be done using ansi escape sequences (even without SetScrollRegion), though it is complicated. And more complicated in conjunction with multiple threads doing output. It is also possible (and somewhat easier in conjunction with threads) using Win32::Console.
There are a couple of ways of tackling the problem.
The basic mechanism is to read the keyboard one character at a time and build up a buffer internally of the keystrokes entered without echoing the characters to the screen as they are entered. I suspect this is what you were attempting to achieve with read in your example. You'd also need to respond to control keys, to effect editing (and history if that's a requirement). This buffer would be a thread-shared scalar.
Each time you output (print) to the screen, from any thread, prefix the output with a return character ("\r"), and also print the contents of the buffer so far, without a newline.
The effect of that looks something like this:
print "\rTHREAD: in da zone !! :) \n", $sharedInputBuffer; ## output THREAD: in da zone !! :) Whatever has been typed so f
The next time some output is produced by a thread, the effect is for the new output to overlay the previous input buffer-load, and again leave the latest buffer-load at the bottom of the output with the cursor at the end:
THREAD: in da zone !! :) THREAD: in da zone !! :)so f Whatever has been typed so far
As you can see, this would leave some artifacts if the output is shorter than the previous amount of 'input'. That's fairly easily fixed by overlaying some extra whitespace or the ClearToEndOfLine (or ClearToEndOfScreen) escape sequences. But it doesn't allow the user feedback from their input until the next output is available. You can cure that by allowing the input routine to update the display (again using "\r") in response to the keystrokes. But, you'll need to ensure that you serialise/coordinate the output from the input thread with that from other threads. It's getting more complicated. It gets more complicated still if you want the user to be able to enter more than a single line at a time. Much more complicated if you want them to be able to edit a long line or more than one line. Ditto for history. Ditto for history lines greater than one line in length. If you've used a *nix console, you've probably seen this.
The mechanics of the above can be greatly simplified by using a different approach to the serialisation of access to the console. Basically, this consists of performing all interactions with the console via a single thread. Output produced by other threads is sent to the console thread (say, via Thread::Queue). And the console thread reads that queue and takes care of the actual output, coordinating it with the echoing/editing of user input. Easier, but still complicated.
The apis available (mostly) via Win32::Console allow you to have different logical handles to STDIN and STDOUT (and STDERR. And actually, multiple of each concurrently). These can be set to occupy different, even overlapping, regions of the actual physical screen. Each of these regions can be written to and read from independently and concurrently, scrolled independantly and concurrently and thread-safely.
The potential for this technique is very powerful, but it can get complicated. Download and run Win32::Console test script to get a feel for some of what is possible.
Either approach is non-trivial. This is why people tend to use graphical interfaces (Tk etc.) for applications that require concurrent, asynchronous user input and application output.
Writing code to handle controlled, asynchronous console IO for your application would require considerable effort to get right. Perhaps more effort than you are prepared to expend for your application.
Ideally, this would be available as a module that you could just plug in and use, but the development would be even more non-trivial. Especially trying to come up with a good simple generic interface.
I have had thoughts on this. The best idea I've come up with so far is that loading the module would override the STDIN, STDOUT & STDERR filehandles, replacing them with tie'd filehandles that would respond to all the usual operations they do, but would also allow each of them to be sized to some subregion of the screen. Or in the case of STDERR, perhaps a completely separate virtual screen that can be switched to, like a browser tab.
All the serialisation, editing, history etc. can be completely hidden behind the STD(IN|OUT|ERR) interfaces. It's a simple and intuative interface that would place minimal design changes upon existing console applications.
The problem is it would take considerable effort to get right and maintain, but how many people would make use of it? There doesn't seem to be a huge demand for this kind of thing.
Developing such a beast for use by a handful of guys who want to write their own chat/irc clients is unappealing. Especially, when so many of them seem to be like you and cannot be bothered to formulate their questions well. Or even format their posts.
In reply to Re: perl threads wait application?
by BrowserUk
in thread perl threads wait application?
by spx2
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |