3

What I've noticed recently in attempting to add some multithreaded functionality to some code of mine for a project at work is that pthreads are a huge pain in the ass to deal with logistically...

Here's the scenario...

I have an infinite loop in my main method (a server) spawning threads to deal with data whenever it receives a packet from whatever client. The problem is that I can't get the threads to execute concurrently at all. They refuse to begin execution until a call to pthread_join() from the main method, which completely kills the whole purpose of using threads in the first place (server needs to STOP execution flow, and wait for the thread to finish processing its data before receiving anymore packets! ridiculous.)

So is there a way to use pthreads and have them actually be multithreaded? Or am I better off not using threads at all, and saving the extra resources by stopping execution in my server to call a function to process data?

I'm thinking I may have to resort to forking everytime...

This is frustrating....

some sample code i did is below:

// gcc threads.c -lpthread
#include <stdio.h>
#include <pthread.h>

struct point{
    int x, y;
};

static void *print_point(void *point_p);

int main() {
    pthread_t tid;
    struct point pt = {3, 5};
    printf("enter main\n");
    pthread_create(&tid, NULL, print_point, &pt);
    while(1){continue;}
    return 0;
}

static void *print_point(void *point_p) {
    struct point arg = * (struct point *) point_p;
    printf("Point: (%d, %d)\n", arg.x, arg.y);
    return NULL;
}

when I run and compile that (yes i compile with the -lpthread switch), it prints "enter main" and doesn't execute the thread... I even let it run for a while (got up, went to the bathroom, ate some food), and still nothing.

So since the main method spawns a thread then loops infinitely, the thread should eventually execute... right? From what I can tell from my tests the main method never gives up execution to the thread it spawned. The only way I can get it to give it up it by calling join (but that defeats the purpose of having threads since main will wait around until the thread is done).

genpfault
  • 51,148
  • 11
  • 85
  • 139
Rob Toth
  • 33
  • 1
  • 3
  • 3
    That works fine for me. Although it's probably inadvisable to have a busy-wait loop in your `main` function; try a big `sleep` instead. – Oliver Charlesworth Jun 21 '11 at 22:14
  • For this particular example, make sure you flush stdout. Otherwise, that short string will be sitting in the output buffer, but not yet printed to the screen because the I/O system is waiting for more data before it bothers printing anything. That shouldn't be the problem with your server program, though. – Rob Kennedy Jun 21 '11 at 22:14
  • 1
    @Rob: Isn't stdout automatically flushed on newlines anyway? – Oliver Charlesworth Jun 21 '11 at 22:16
  • 2
    tight loops like `while(1){continue;}` may cause scheduling issues. Instead, use `sleep` to ensure the OS has a chance to reschedule. Make sure you do that in your server application, may be that's the problem (although in your server you're probably waiting on `select` or something?) – littleadv Jun 21 '11 at 22:19
  • +1 to Oli's comment: Use a sleep to force a context switch. You're not going to be guaranteed that with a while(true) loop. – dolphy Jun 21 '11 at 22:20
  • @Rob: yeah stdout is flushed automatically. tried adding that in and the output doesn't change. – Rob Toth Jun 21 '11 at 22:20
  • Ah, yes, @Oli and Rob are right. Sorry, then; I'm stumped. – Rob Kennedy Jun 21 '11 at 22:23
  • OS? Hardware? Compiler version? Full compiler invocation? – genpfault Jun 21 '11 at 22:28
  • (server needs to STOP execution flow, and wait for the thread to finish processing its data before receiving anymore packets! ridiculous.) Why does the server have to stop? – Martin James Jun 21 '11 at 23:57
  • did u edit the post?. coz it works fine for me. – Pritesh Acharya May 09 '13 at 11:20

2 Answers2

5

You're never giving the thread a chance to execute with that while(1){continue;}. One of two things will happen here.

  1. You've compiled with high enough optimization that the compiler makes that entire loop vanish. The thread never gets a chance to execute because main starts the thread and then immediately returns zero.
  2. The compiler doesn't optimize the loop away. With this busy loop you once again are not giving the thread mechanism a chance to slip in.

Add a sleep (0); call to the body of that busy loop.

David Hammen
  • 32,454
  • 9
  • 60
  • 108
2

Actually your code works fine for me, but I think your problem is that the main thread is sitting in that while() loop, hogging all the CPU usage, so the second thread never gets a chance. The fact that pthread_join makes it work is a bit of a red herring: it's just stopping the main thread so the other threads get a chance.

Obviously the right fix for this is to make the main thread sleep properly when it has nothing to do. For your test code, try putting sleep(1) in your while loop.

richvdh
  • 1,163
  • 11
  • 19
  • 2
    sleep(0) also works. One second is a long time in dog years, even longer in CPU years. Calling sleep(0) is a standard trick to give some other thread a chance to hog the CPU. – David Hammen Jun 21 '11 at 22:27
  • @Rob: Note its not the sleep(0) you need. Its to get the main thread to pause for a second (don't take that second literally) to give the other threads the opportunity to run. sleep(0) is just a simple trick that shows this. If you are doing a real server you will use a call to something like select() which will have the same affect. – Martin York Jun 21 '11 at 23:04
  • @David: that's true. I guess pthread_yield() is a more explicit way of achieving the same thing as a sleep(0). – richvdh Jun 22 '11 at 10:15
  • @Martin: The problem here was that Rob was never releasing the CPU. I agree that in a real application something other than `sleep()` is needed in a real application. Something to read incoming packets, for example. I didn't want to go into the details of how to use `select()` to do that. OTOH, calling sleep(0) is a typical trick used to have a CPU-bound thread temporarily relinquish control of the CPU. The non-standard `pthread_yield()` or the standard `sched_yield()` is sometimes a bit too heavy-handed. – David Hammen Jun 22 '11 at 12:00