[vox-tech] a better scanf?? (C-programming question)

Andy Campbell vox-tech@lists.lugod.org
Fri, 18 Apr 2003 15:44:12 -0700


Thank you for all the good info. Actually, it sounds like using a threaded
approach would be best. I am actually relatively familiar with threads. This
whole program is just a free time man-machine interface in user space for a
real-time motor controller that I have running in the RT-Linux kernel. In
the kernel space code, I have two threads running. It is funny, because I
have kinda learned how to do it there first (with the help of RT-Linux
documentation), but I don't really know how to create a multithreaded
program in user space. What is a good command that I can check in the man
pages and learn in order to implement a multithreaded user space program??

Overall, you have definitely given me much knowledge and several avenues to
pursue. Thank you very much for your time and patience!

Andy

>
> When you're developing for unix, you have two different sets of functions
> for doing file I/O:
>
> * The unix operating system provides a set of functions which use file
> descriptors: open(), close(), read(), write(), etc. These functions are
> generally provided by the operating system kernel.
>
> * The C language standard defines a different set of functions that use
> file handles (not descriptors): fopen(), fclose(), printf(), etc. These
> are commonly called stdio or "standard I/O". These functions are normally
> implemented as library functions (i.e. code running outside of the
> kernel, just like the functions you write) which call the
> operating-system routines in order to perform actual I/O.
>
> stdin, stdout, and stderr are file handles, not descriptors. They're
> strictly used with the stdio functions, not the OS functions. Further,
> they're generally already open when your program starts up so it isn't
> necessary to open() or fopen() them.
>
> Now let's talk about ttys. If your program is interacting with a human
> than it's probably through a tty device. This is a unix OS construct that
> provides things like the backspace key and killing a program by typing
> ^C.  If you want to do non-blocking reads from a tty you have to
> understand a bit about how ttys work.
>
> ttys have three operating modes: line-at-a-time (or "cooked"), cbreak, or
> raw. In raw mode, every character typed by the user is immediately
> available to the program. cbreak mode is much like raw mode, but some
> characters receive special handling, e.g. ^C. In cooked mode, the tty
> driver buffers data typed by the user (and handles line-editing such as
> backspace, ^U, etc.) until the user hits return or ^D. When the user hits
> one of these, the entire line of input becomes available for the program
> to read.
>
> You generally don't use stdio routines to do nonblocking input. The stdio
> library doesn't provide any standard means to see if data is waiting to
> be read without blocking. For example, getchar() always returns either a
> character or an EOF indication. There's no getchar return value that
> means "not EOF but not valid, either". Similarly, when you use fgets() to
> read a line, fgets will block until it reads an entire line. Even reading
> from a tty in cbreak mode, with characters dribbling in as the user types
> them, fgets() won't return control until it gets that newline character.
>
> So if you want to do non-blocking reads you have to use the OS routines
> to do it, rather than the stdio routines. The os routine is called
> read(), but it also blocks until data becomes available. There are two
> ways around that:
>
> 1) Use select() or poll() to test the file descriptor first; perform the
> read() only if select/poll indicates you can do it without blocking.
>
> 2) Set the file descriptor to nonblocking at open() time or by using
> fcntl(). Then, if you call read() and no data is waiting, then read()
> will return -1 and errno will be set to EWOULDBLOCK.
>
> Either way, every time you read in some data, you'll need to save it in a
> buffer somewhere until you've read a newline (or whatever marks the end
> of the input). Then you can call sscanf() to parse the buffer contents if
> you like.
>
> Since you'll be using read() and select()/poll(), you'll need to know
> what file descriptor to use. You can do any of three things:
>
> 1) call fileno(stdin). fileno() returns the file descriptor associated
> with a file handle.
>
> 2) Just use 0. File descriptors are just numbers. 0 is standard input, 1,
> is standard output, and 2 is standard error.
>
> 3) Forget about using stdin. Call open("/dev/tty", O_RDWR) instead. This
> avoids the question of what to do if standard input isn't actually a tty
> device for some reason (e.g., because the user redirected input when he
> launched the program).
>
> By now you're probably wishing there were an easier way. There are at
> least three alternatives to doing all of this:
>
> 1) Use curses/ncurses. Curses is a library for doing fancy operations on
> terminals, such as positioning the cursor or printing boldface text.
> Among its features, it includes a set of functions for doing nonblocking
> character input.
>
> 2) Use separate processes. Call fork() and let the child process perform
> the operations that shouldn't be interrupted while the parent process
> interacts with the user.
>
> 3) Use separate threads. A thread is your execution context, i.e. the
> part of the program being executed at any given time and its local
> variables. Under the classic program model that you're probably used to,
> a running program only has one thread, but it's possible to start
> additional threads. The benefit is that a single thread can perform an
> operation that blocks (for example, using stdio to read a line from the
> user) without preventing other threads from executing.
>
> Threads have a reputation for being difficult to work with. It's true
> there's a bit of a learning curve, but personally I've never had much
> trouble with them. They're definitely the wave of the future; java
> contains sophisticated thread support, and most complex GUI-driven
> programs are multithreaded. If you aspire to do serious programming
> you'll probably end up learning them anyway; better to do it now before
> you develop a lot of bad programming habits.
>
> --
> Kenneth Herron  Kherron@newsguy.com     916-366-7338
> _______________________________________________
> vox-tech mailing list
> vox-tech@lists.lugod.org
> http://lists.lugod.org/mailman/listinfo/vox-tech
>