I / O Migration for Windows-Centric for Linux

I am developing a Windows application that has a separate thread for processing a user (or third-party) application through stdin.

This thread is designed in such a way that it waits through WaitForMultipleObjects two events:

  • Signal of death . When this signal rises, the interface processing flow is turned off.
  • Interface signal . When this signal is raised, the input is ready to read. The input is read and processed.

On Windows, this thread enters the main loop, where Wait for these two events (where bWaitAll is FALSE ). Waiting for the stdin descriptor has a signaling effect when there is a read-in input, and another event is set elsewhere in the application.

It works exactly the way I want. He expects the event to be raised without entering a lively expectation, and he will expect both events at the same time.

I want to port this functionality to Linux, but I'm not sure how to achieve the desired result. Essentially, I really want:

On Linux, how do I create a thread so that it responds immediately to user input on stdin, but it can also respond immediately so that the death flag is raised from another location in the application?

To accomplish the latter, it seems to me that I cannot use cin , gets , getch or any other function that blocks until the user enters text. However, I do not know how to read user input in a console application without blocking.

I am open to any changes in architecture (if there are more features for Linux-y), which include entering user input into a separate stream, which can be removed from another place in the application. I am using GCC 4.4 and Boost 1.51.

+4
source share
2 answers

The standard way to do this on Linux is to use the select(2) system call. However, select more limited than WaitForMultipleObjects , since it can only wait for file descriptors, and not other types of objects (for example, events). So a typical way of working on this is to create a channel and write a dummy value to the channel as your “signal”.

Something like that:

 // Error checking omitted for expository purposes int pipefd[2]; pipe(pipefd); // Create the pipe while(1) { // Create file descriptor set of stdin and the read end of the pipe fd_set fds; FD_ZERO(&fds); FD_SET(STDIN_FILENO, &fds); FD_SET(pipefd[0], &fds); int maxfd = MAX(STDIN_FILENO, pipefd[0]); // Wait until input becomes available on either stdin or the pipe int num_available = select(&fds, NULL, NULL, NULL); // Read & process stdin if possible (will not block) if (FD_ISSET(STDIN_FILENO, &fds)) { int n = read(STDIN_FILENO, buffer, size); ... } // Read & process pipe if possible (will not block) if (FD_ISSET(pipefd[0], &fds)) { char dummy; read(pipefd[0], &dummy, 1); // Handle signal (eg break out of loop) } } 

Then, to report this stream, simply write one byte at the end of the record in the handset:

 char dummy = 42; write(pipefd[1], &dummy, 1); 
+3
source

libev (and several similar incarnations) offers a convenient abstraction around select , including the ability to defer to signal s.

If you have the option to change the Source of the Interface Signal , you can consider changing it to use raise instead.

+1
source

Source: https://habr.com/ru/post/1444466/


All Articles