Thread: Help with non-blocking IO

  1. #1
    Registered User
    Join Date
    Jan 2011
    Posts
    3

    Help with non-blocking IO

    Hi everyone,

    New user on this forum but also new to C and C++.

    I was hoping someone could enlight a really beginner on something I've been struggling with in the last days.

    Here is my task for an R&D Project. I've build a client app and a server app using sockets with Adobe AIR. Works well so far.

    The server app is including a C compiled executable to act as a wrapper for another C library.

    I've made the front (server app) talking with the C process that I launch from it. The app is basically able to send and receive data with the C process (just string for now). Pretty much like you would do from with command line.

    I had 2 approaches to exchange data (just string for now):

    - std::cin and std::cout
    - read and write

    They both work well.

    The problem:

    The C library I've included is using a thread to get information from a server, I made it working with some examples I had, but the example is using a usleep and it makes the while loop stopping which is a problem with the I/O I need (if I got the code right). Also the std::cin and read method stops the while loop which is a problem as I need to loop for the thread to process the events I receive from the server.

    With a bit of search, I found out that what I probably need is called "non-blocking IO".

    Great, but my knowledge of C is so light that I haven't been able to make any non-blocking IO examples working (I have like 6 google pages of visited links I tried to find a solution I would be able to able to understand/implement at my level)...

    The closest I got is the following code (also attached as a file), which stops looping as soon as I receive an input (basically not working).

    I was hoping someone could explain me a bit how I can do that (simply if possible, as I'm really a beginner), the best would be a simple command line program that shows the loop and IO working? Or tell me what is wrong in that code, in which I understand only half of it, as I tried bits and pieces from everywhere.

    I understand I need to put my nose in some C, C++ book, which I will do, but right now, having this non-blocking IO working would make me able to continue.

    Thanks in advance for any help.

    Romuald

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <string.h>
    #include <signal.h>
    #include <pthread.h>
    
    #include <string>
    #include <sstream>
    #include <iostream>
    
    #include "appkey.h"
    #include "libspotify/api.h"
    #include "spotify.h"
    
    #include <sys/socket.h>
    #include <termios.h>
    
    #define STDIN 0  // file descriptor for standard input
    #define BUFFER_SIZE 8192 
    #define NB_ENABLE 0
    #define NB_DISABLE 1
    
    bool exitloop = false;
    pthread_t mainthread = 0;
    char buf[BUFFER_SIZE];
    
    static void sigIgn(int signo) { }
    
    int kbhit() {
        struct timeval tv;
        fd_set fds;
        tv.tv_sec = 0;
        tv.tv_usec = 0;
        FD_ZERO(&fds);
        FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0
        select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
        return FD_ISSET(STDIN_FILENO, &fds);
    }
    
    void nonblock(int state) {
        struct termios ttystate;
        //get the terminal state
        tcgetattr(STDIN_FILENO, &ttystate);
        if (state==NB_ENABLE) {
            //turn off canonical mode
            ttystate.c_lflag &= ~ICANON;
            //minimum of number input read.
            ttystate.c_cc[VMIN] = 1;
        }
        else if (state==NB_DISABLE) {
            //turn on canonical mode
            ttystate.c_lflag |= ICANON;
        }
        //set the terminal attributes.
        tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
    }
    
    int main(int argc, char* argv[]) {
        int i = 0;
    	int cnt; 
    	mainthread = pthread_self();
    	signal(SIGIO, &sigIgn);
    	if(spotify->InitSession())
    		printf("valid session.\n");
    	else
    		printf("invalid session.\n");
    	spotify->SetCredentials("*************", "**************");
    	spotify->Login();
    	sigset_t sigset;
    	sigemptyset(&sigset);
    	sigaddset(&sigset, SIGIO);
        nonblock(NB_ENABLE);
        while(!i) {
            i=kbhit();
            if (i!=0) {
    			while (!feof(stdin)) { 
    				cnt = read(STDIN_FILENO, buf, sizeof buf); 
    				write(STDOUT_FILENO, buf, cnt );
    			} 
            }
    		int timeout = -1;
    		pthread_sigmask(SIG_BLOCK, &sigset, NULL);
    		spotify->ProcessEvents(&timeout);
    		pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
        }
        nonblock(NB_DISABLE);
        return 0;
    }

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Non-blocking I/O (which involves control returning to your code, while I/O is pending, and eventually there being some alert or signal upon completion of the I/O, so your code can retrieve results) is not actually part of the C library. Nor, for that matter, are threads and sockets.

    The support of those things depend on additional capabilities supplied with your operating system, or with ancillary libraries.

    As such, you will need to read appropriate documentation (eg man pages) to work out what is possible on your system. You won't get it be reading up on C, unless your C textbook happens to be written around your particular target system.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  3. #3
    Registered User
    Join Date
    Jan 2011
    Posts
    3
    Right, that sounds harder than I thought.

    The server where we will be using this server app will a Mac. We don't do anything cross-platform right now.

    Could you tell where should I start then?

    Thanks for your answer.

    Romu

  4. #4
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    On Mac OS X, check out kqueue(): works with sockets but not tty's, apparently. The FreeBSD forum should have more info on this, since OSX is based on that, and they have Asynchronous IO in FreeBSD.

    Source:
    Asynchronous I/O - Wikipedia, the free encyclopedia

    Certainly above my pay grade, as a programmer.

  5. #5
    Registered User
    Join Date
    Jan 2011
    Posts
    3
    Hi again,

    Thanks for that information, I'll dig into that.

    If I can ask again, as I had a go with another piece of code.

    In the following code, I used the select() and I can now loop to get the input and perform the thread every second.

    But I get an error in the console "select(): Interrupted system call" while I call a "processEvent" method on the library (code not visible).

    Code:
    spotify->ProcessEvents(&timeout);
    This wasn't hapening in the first piece of code I posted.

    Any idea what that that is, what could interupt a this select call or how I could solve it?

    Thanks again for your time.

    Romu

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <string.h>
    #include <signal.h>
    #include <pthread.h>
    
    #include <string>
    #include <sstream>
    #include <iostream>
    
    #include "appkey.h"
    #include "libspotify/api.h"
    #include "spotify.h"
    
    #include <sys/socket.h>
    #include <termios.h>
    
    #define BUFFER_SIZE 8195
    #define FD_NUM 0
    
    fd_set rfds;
    struct timeval tv;
    int retval;
    int cnt;
    int readResult;
    char buffer[BUFFER_SIZE];
    pthread_t mainthread = 0;
    
    static void sigIgn(int signo) { }
    
    int timed() {
    	
    	/* Watch stdin (fd 0) to see when it has input. */
    	FD_ZERO(&rfds);
    	FD_SET(FD_NUM, &rfds);
    	
    	/* Wait up to five seconds. */
    	tv.tv_sec = 1;
    	tv.tv_usec = 0;
    	
    	retval = select(1, &rfds, NULL, NULL, &tv);
    	/* Don't rely on the value of tv now! */
    	
    	if (retval == -1) {
    		perror("select()");
    		return 0;
    	}
    	else if (retval) {
    		/* FD_ISSET(0, &rfds) will be true. */
    		readResult = read(FD_NUM, buffer, BUFFER_SIZE);
    		printf("Data is available now: %s\n", buffer);
    		
    		//write(0, buffer, cnt);
    		
    		return 1;
    	}
    	else {
    		printf("No data within five seconds.\n");
    		return 2;
    	}
    }
    
    int main(void) {
    	
    	mainthread = pthread_self();
    	signal(SIGIO, &sigIgn);
    	
    	if(spotify->InitSession())
    		printf("valid session.\n");
    	else
    		printf("invalid session.\n");
    	
    	spotify->SetCredentials("breellondon", "spotifybreel1234");
    	spotify->Login();
    	
    	sigset_t sigset;
    	sigemptyset(&sigset);
    	sigaddset(&sigset, SIGIO);
    	
    	while (timed() != 0) {
    		
    		std::cout << "looping true\n";
    		
    		int timeout = -1;
    		pthread_sigmask(SIG_BLOCK, &sigset, NULL);
    		spotify->ProcessEvents(&timeout);
    		pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
    		
    	}
    	
    	return 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Socket blocking & end to end delay
    By nabi in forum Networking/Device Communication
    Replies: 4
    Last Post: 10-29-2010, 10:47 AM
  2. Should I use threads to do the file io
    By jeanluca in forum C Programming
    Replies: 7
    Last Post: 04-25-2010, 12:15 PM
  3. How to initialize a non blocking socket using only winsock library
    By *DEAD* in forum Networking/Device Communication
    Replies: 4
    Last Post: 01-18-2008, 07:03 AM
  4. File IO with .Net SDK and platform SDK
    By AtomRiot in forum Windows Programming
    Replies: 5
    Last Post: 12-14-2004, 10:18 AM
  5. Totally puzzling IO problem
    By Vorok in forum C++ Programming
    Replies: 5
    Last Post: 01-06-2003, 07:10 PM