Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Multithreaded ncurses

This thread is locked; no one can reply to it. rss feed Print
Multithreaded ncurses
gillius
Member #119
April 2000

OK, so I've discovered that there is a problem in the multithreaded consoel library in my GNE library.

The question: is there a way in ncurses to read input from one thread using blocking while allowing concurrent updates from another thread? I'm thinking the answer is no.

The details: ncurses is not thread-safe, and I realize that. The problem is that in the original GNE code I assumed that it was safe to do output and input at the same time (but not two doing output or two doing input). So I used a mutex to protect calls and designed an API to make common groups of operations (like move and print) to be atomic. However, I couldn't put the same mutex on the input functions, like getch. Why? Because getch blocks for a key, which means that if a thread is waiting for input there can be no output.

Practically speaking, I hadn't seen any problems from this for actually a few years on Windows, Linux, or Solaris. But recently on a Red Hat-based server with dual HT processors (4 concurrent threads) and connecting from PuTTY, I saw some problems with my "exinput" example which has something like 50 threads doing output and 1 thread doing a buy loop on kbhit (which calls a non-blocking getch).

What happens is that if the getch is called at the same time as a putchar call, then I'll see some random ANSI garbage being printed; my guess here being that there are mixtures of ANSI codes being output to the screen -- but getch shouldn't be sending output to the terminal. Another idea is that getch is modifying some static states in curses that is causing move and print functions to mess up.

When I put a mutex around the kbhit, the problems all go away so I am pretty convinced that this is a threading problem and not a problem with the TTY implementation on the Linux server or with PuTTY. For kbhit, a mutex is fine since kbhit is a polling function. But this is not possible when using a blocking getch, because if I take the single-threaded requirement strictly, I can't call anything while the getch is blocked.

The only solution I can imagine now is to use halfdelay in curses to cause getch to block for a short time, then explictly check to see if anyone is wanting to do some output and do that. This would be easy to do except that mutexes in pthreads are not guaranteed to be fair, so I have to do some more work, as busy-waiting with a mutex could starve threads waiting on the mutex.

Gillius
Gillius's Programming -- https://gillius.org/

Steve Terry
Member #1,989
March 2002
avatar

I think you can set stdio to non-blocking, I've seen it done before since it really is just a file stream, then you wouldn't need threading neccessarily.

[edit]
nm the question is more complex than when I first scanned over it :P
[/edit]

___________________________________
[ Facebook ]
Microsoft is not the Borg collective. The Borg collective has got proper networking. - planetspace.de
Bill Gates is in fact Shawn Hargreaves' ßî+çh. - Gideon Weems

gillius
Member #119
April 2000

Yeah, I guess I assumed that curses was not capable of multi-threading, but I was hoping that as long as I only accessed output from one thread and input from one thread I'd be OK -- kinda like the separation between stdout and stdin as two separate streams. Apparently this isn't the case. Scanning the man pages, I can only see halfdelay as a solution.

I know that if ncurses has zero threading support, then there is no way around this issue, because the only way to satisfy the single-thread rule is to have a callback in ncurses (which it wouldn't have) when data is ready, or something else that is asynchronous or pseduo-asynchronous.

What I was trying to research and hoping that people might be able to answer me is if it is safe to do something like wait on stdin using select or something similar that does not use curses to block for input. Basically the only thing I need to do is simply know when a call to getch will actually return a key and not block without having to poll. I don't need to interact with ncurses otherwise during this time, so as I know the underlying I/O layer in the OS is thread safe, it should be fine. But can I do it without any bad assumptions about how ncurses and stdin interact?

Gillius
Gillius's Programming -- https://gillius.org/

Go to: