Thread: What model should I use when sending receiving packets?

  1. #1
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485

    What model should I use when sending receiving packets?

    I'm working on a program that sends of a sound to a device in packets, when it's time to send of the packets I need to wait for a confirmation that the packet got to the destination and all is well before sending the next one.

    Up until the sending part of my program everything is done in one thread. What I want to do is to do the sending in a new thread then use some mechanism in pthreads library to put it to sleep until I get the notification back from the receiving end.

    I've been thinking about using a mutex but since I'm not really trying to protect a shared resource here I don't think this might be the best option. All I wan't is to wait for a condition to be true. I'm most familiar with the mutex though, and it might work to the same effect, although I'm a bit uncertain what would happen if I for some reason got a confirmation from the receiving end before I managed to pass the lock to the main thread?

    Is the pthreads conditional variables a better choice in this case? What I would like to know basically, is if there are some tried and often used pattern I can apply here.

    Thanks

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    What sort of device, across what sort of interface?

    Down to the other end of the PCI bus is going to be well below 1uS. By the time the OS has gotten around to thinking about anything else with threads, the answer will already be available.

    A random server on the web with ping times in 10's of milliseconds is another matter entirely.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by Salem View Post
    What sort of device, across what sort of interface?
    It's a musical instrument (a sampler) and the interface is midi. The instrument is connected with a cable to my interface (usb). I would think that the situation should not happen where I get a response before I manage to pass the lock to the main thread. But, the main thread uses a callback function that is handed in to a library function which is high priority realtime process. My own program could perhaps be interrupted by something, causing a delay. But all this is just speculation, I would not think that this should happen.

    But let's say that it did happen what would happen if my main thread with the callback was sleeping, would it receive the notification at all?


    Edit: to clarify my midi-interface is an usb device, so the chain looks like this: [computer]---usb--->[midi-interface]---midi--->[sampler]
    Last edited by Subsonics; 04-25-2010 at 02:23 PM.

  4. #4
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    After a bit of reading I think the best approach for me in this situation would be to use semaphores. Simpler that conditional variables and sufficient here since the only thing I need the callback to do is, check the arriving packet, set a flag to ACK, NACK, WAIT or CANCEL as well as call sem_post(). The sending thread then calls sem_wait() and sends of the next packet in the queue.

    To get my feet wet I have tried with some simple examples but I'm running in to some problems, perhaps someone here with more experience can see what I am doing wrong.

    Here is a bs program that does nothing but print 1's and 2's.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <semaphore.h>
    
    pthread_t new_thread;
    sem_t sem;
    
    void *thread_print(){
            while(1){
                    sem_wait(&sem);
                    puts("1");
            }
    }
    
    void print_main(){
            while(1){
                    puts("2");
                    sem_post(&sem);
            }
    }
    
    int main()
    {
            int err = pthread_create( &new_thread, NULL, thread_print, NULL);
            if(err)
                    exit(1);
    
            print_main();
    
            return 0;
    }
    Now if redirect the output into a file and use:

    Code:
    cat test | grep 1 | wc -l
    and

    Code:
    cat test | grep 2 | wc -l
    I would expect there to always be more 2's than 1's (or equal), since the main thread can print as much as it pleases and increment the semaphore, while the other thread can only print until the semaphore reaches 0. However this is not always the case, sometimes there are more 1's than 2's in the file.

    What am I doing wrong here?

  5. #5
    Registered User
    Join Date
    Oct 2008
    Posts
    1,262
    Well, for one, you're not initializing the semaphore see sem_init).

  6. #6
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Ah, that might be the ticket, forgot to do that, I remember reading about it the other day. Thank you.

  7. #7
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Hm, I still can't get this to work, the sem_init returns -1. This is how I do it:

    Code:
            err = sem_init( &sem, false, 0 );
            if(err == -1){
                    printf("Sem_init returned: %d\n", err);
                    exit(1);
            }
    This is from pthreads primer:

    Code:
    sem_t requests_length;
    
    sem_init(&requests_length, TRUE, 10);
    I have included stdbool.h and the only difference AFAK is that the last example should make the semaphore available to other processes which I'm not interested in and init it to 10 instead of 0.

    Quote Originally Posted by Open Group
    RETURN VALUE

    Upon successful completion, the function initialises the semaphore in sem. Otherwise, it returns -1 and sets errno to indicate the error.
    Last edited by Subsonics; 04-30-2010 at 09:41 AM.

  8. #8
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Apparently unnamed semaphores and sem_init is not supported on my system, I need to use sem_open instead.

  9. #9
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Ok, I'm now using sem_open instead, and I have added a global variable "i" that one thread increments and the other decrements. I still have the same problem, the thread with the sem_wait call should go to sleep if the semaphore reaches zero so no negative values of "i" should be possible if this worked.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <semaphore.h>
    
    pthread_t new_thread;
    sem_t *sem = NULL;
    int i = 0;
    
    void *thread_print(){
    
            while(1){
                    sem_wait(sem);
                    i--;
                    printf("1: %d\n", i);
            }
    }
    
    void print_main(){
    
            while(1){
                    i++;
                    printf("2: %d\n", i);
                    sem_post(sem);
            }
    }
    
    int main()
    {
            sem = sem_open("semaphore", O_CREAT, 0, 0);
            if(!sem)
                    exit(1);
    
            int err = pthread_create( &new_thread, NULL, thread_print, NULL);
            if(err)
                    exit(1);
    
    
    
            print_main();
    
            sem_close(sem);
            return 0;
    }
    The thing I'm a bit unsure about is the third argument in sem_open it's for setting permissions, it can be left out so I just set it to zero, the last parameter is the initial value of the semaphore.

  10. #10
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    What is your system and compiler?

    * You need <fcntl.h> for O_CREAT.
    * thread_print() has wrong signature - it needs to take a void* parameter (even if you don't use it).

    >> The thing I'm a bit unsure about is the third argument in sem_open
    I believe 0 will ensure that only a single process instance can use that semaphore. If you don't close it properly (which you can't due to infinite loops) then you may not even be able to run your application again until you reboot (seems to be the case with Linux - unless there is an "ipcrm" style command for posix semaphores).

    >> I still have the same problem...
    What problem is that? It does exactly what I would expect - both threads run as fast as they can - i never goes below 0.

    Named semaphores are overkill for synchronization within a single process. Just use pthread_mutex_t and pthread_cond_t. Example usage here: Mutex, Cond and Thread questions (pthread, linux)

    gg

  11. #11
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by Codeplug View Post
    What is your system and compiler?
    OS X, gcc-4.2.1.

    Quote Originally Posted by Codeplug View Post
    * You need <fcntl.h> for O_CREAT.
    * thread_print() has wrong signature - it needs to take a void* parameter (even if you don't use it).
    Thanks, I've fixed this now.

    Quote Originally Posted by Codeplug View Post
    >> The thing I'm a bit unsure about is the third argument in sem_open
    I believe 0 will ensure that only a single process instance can use that semaphore. If you don't close it properly (which you can't due to infinite loops) then you may not even be able to run your application again until you reboot (seems to be the case with Linux - unless there is an "ipcrm" style command for posix semaphores).

    >> I still have the same problem...
    What problem is that? It does exactly what I would expect - both threads run as fast as they can - i never goes below 0.
    Hm, here it does go below zero on occasions so I assumed that I had missed some detail somewhere. I might just abandon it for the example below now though, lol.

    Quote Originally Posted by Codeplug View Post
    Named semaphores are overkill for synchronization within a single process. Just use pthread_mutex_t and pthread_cond_t. Example usage here: Mutex, Cond and Thread questions (pthread, linux)

    gg
    Thanks for that, I will look into it.
    Last edited by Subsonics; 04-30-2010 at 03:09 PM.

  12. #12
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    I got things working with the conditional variables, thanks for the link.

    I'm a bit curious about the semaphore example above though. I noticed that there is a while loop in the other example that polls for a change of the global variable. I tried to do the same on the above example and then it seems to work. Q: Is it then also necessary to do this sort of polling with semaphores? I was under the impression that this was done in the background for me, if the semaphore reaches 0.

    Here is what I added to get things working:

    Code:
    void *thread_print(void *a){
    
            while(1){
                    while(i == 0)
                            sem_wait(sem);
                    i--;
                    printf("1: %d\n", i);
            }
    }
    It seems a bit redundant, since this thread should be put to sleep if the semaphore reaches 0, if I have understood it correctly.


    Edit: I added a sleep(1) to the producer thread, then looked at things in top. It appears that this polling gives me near 100% cpu usage, so I guess that answers the question then lol.
    Last edited by Subsonics; 05-01-2010 at 07:49 AM.

  13. #13
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> It does exactly what I would expect - both threads run as fast as they can - i never goes below 0.
    That was a bad expectation on my part. The accesses to i are unsynchronized, so you can't expect anything from i's value. If all threads access i while holding a pthread_mutex_t, then i will never go below 0.

    >> Is it then also necessary to do this sort of polling with semaphores?
    No. You don't need to poll with Posix semaphores. They just work as advertised - wait blocks while the value is 0, post increments value by 1 and releases at most 1 waiter.

    Pthread condition variables, in the interest of efficiency, are allowed to have "spurious wakeups". This means that more than one thread can return from its pthread_cond_wait() call after a single call to pthread_cond_signal(). This is why you need a "predicate condition" that lets the waking thread know if it should continue or go back to waiting.

    gg

  14. #14
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by Codeplug View Post
    >> It does exactly what I would expect - both threads run as fast as they can - i never goes below 0.
    That was a bad expectation on my part. The accesses to i are unsynchronized, so you can't expect anything from i's value. If all threads access i while holding a pthread_mutex_t, then i will never go below 0.

    >> Is it then also necessary to do this sort of polling with semaphores?
    No. You don't need to poll with Posix semaphores. They just work as advertised - wait blocks while the value is 0, post increments value by 1 and releases at most 1 waiter.
    Ah, ok I see. Thanks

    Quote Originally Posted by Codeplug View Post
    Pthread condition variables, in the interest of efficiency, are allowed to have "spurious wakeups". This means that more than one thread can return from its pthread_cond_wait() call after a single call to pthread_cond_signal(). This is why you need a "predicate condition" that lets the waking thread know if it should continue or go back to waiting.

    gg
    Ok, so in my case, having just one extra thread I guess I can leave it out then with out issues. I tested without it and just the conditional variable, waking up my consumer thread every time I hit enter on stdin to simulate what the call back will do. So far it has worked perfectly.

    Thanks
    Last edited by Subsonics; 05-01-2010 at 10:58 AM.

  15. #15
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> I guess I can leave it out then with out issues.
    Posix says you should always have a predicate. So an implementation may interpret that to allow other types of "spurious wakeups" (that may break you code).
    http://www.opengroup.org/onlinepubs/9699919799/toc.htm

    Another issue with not using predicates is that calling cond_signal() will only release thread(s) currently blocked in a cond_wait() call.
    So if you only have thread A and B:
    1) A calls cond_signal()
    2) B returns from cond_wait(), processes something
    3) A calls cond_signal() again
    4) B calls cond_wait() and never processes the second signal.

    Always use a predicate.

    gg

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Sending ARP packets
    By Poincare in forum C Programming
    Replies: 5
    Last Post: 07-15-2009, 09:02 AM
  2. Client/server problem; server either stops receiving data or client stops sending
    By robot-ic in forum Networking/Device Communication
    Replies: 10
    Last Post: 02-16-2009, 11:45 AM
  3. socket message sending and receiving problem
    By black in forum C Programming
    Replies: 5
    Last Post: 01-15-2007, 04:46 AM
  4. Help with file reading/dynamic memory allocation
    By Quasar in forum C++ Programming
    Replies: 4
    Last Post: 05-17-2004, 03:36 PM
  5. Sending raw packets.
    By Denethor2000 in forum C++ Programming
    Replies: 3
    Last Post: 06-04-2002, 02:08 PM