简体   繁体   中英

How to stop and continue a pthread?

I'm coding in C (actually in OOC which is then compiled to C).

How do I instruct a thread to wait at a particular checkpoint until some other thread tells it to continue?

I'm actually using a tight loop in the thread and polling a variable I'm changing from the main thread, but I think that is not well performing, right? Besides that, when I do a tight loop in a thread, should I include a sleep in the loop to avoid consuming much cpu power just looping?

It seems that you are looking for pthread_cond_wait and its related functions.

Here is a quote from the manpage with an example:

Consider two shared variables x and y, protected by the mutex mut, and a condition variable cond that is to be signaled whenever x becomes greater than y.

  int x,y; pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 

Waiting until x is greater than y is performed as follows:

  pthread_mutex_lock(&mut); while (x <= y) { pthread_cond_wait(&cond, &mut); } /* operate on x and y */ pthread_mutex_unlock(&mut); 

Modifications on x and y that may cause x to become greater than y should signal the condition if needed:

  pthread_mutex_lock(&mut); /* modify x and y */ if (x > y) pthread_cond_broadcast(&cond); pthread_mutex_unlock(&mut); 

In the end it does what you are asking for: the thread calling pthread_cond_wait(&cond) is blocked until an other thread (your main thread for example) calls pthread_cond_broadcast(&cond) . During this time it is just in a blocked state and doesn't consume CPU cycles.

I think that's a good candidate for a condition. The thread should wait on a condition and the other thread should signal the condition to let this thread continue.

you can lookup pthread_cond_init and that should lead to other functions

You should look into proper synchronisation primitives such as mutexes, condition variables and semaphores. In this case, it sounds like a condition variable is the most appropriate tool from the pthreads library.

Just so you know what was going on, a "tight loop" consumes your thread's CPU allotment just like any other code your thread executes. The only difference is that it accomplishes nothing. Well I guess making the core warm is something... You probably never want to do that unless you care about the cost of the context switch and you know for sure that the wait time is going to be much shorter than your thread's timeslice, which is about 1ms. I don't know if sleep is as bad as yield (AFAIK yield sets your thread the the back of the list of threads to activate at your priority level) , but both at least incur the penalty of a context switch. There is a cost to context switching. A context switch is what happens when your thread's timeslice ends. It can either end because you ended it with a yield or a sleep, or if the kernel ended it by pre-empting you. Read about SMP and spinlocks to understand more about context switches and cases when a tight loop is applicable.

Also, when you sleep, you don't exactly know when you will wake up again. so one reason you might not want to sleep is you need to get something done fast. You could wait a couple ms before being rescheduled.

Everyone else gave you the pthread_cond_wait solution, which requires locking via mutexes and looks straightforward and simple. The performance might be adequate for your needs, but is relatively slow compared to a solution using signals ( sigwait and pthread_kill ). The complexity will sneak up on you.

Not discussed here is why you lock a mutex before testing if you need to wait on the condition. The reason is that code like this has a flaw:

      while (x <= y) {
              pthread_cond_wait(&cond, &mut);
      }

Your thread could test ( X<=Y ), see that it has to wait, but be pre-epted before it attaches itself to the condition value. Some other thread, who just modified x or y, signals the condition in that timeslice before the first thread attaches to the condition. In this way, the condition signal is lost. So what ends up happening is everywhere you modify the variables afecting the signal, you have to add locks.

      pthread_mutex_lock(&mut);
      /* modify x and y */
      if (x > y) pthread_cond_broadcast(&cond);
      pthread_mutex_unlock(&mut);

This may mean you add these mutex locks in many different places and your code gets more complex and slower because of that. The possibility of a hung thread waiting for a condition is always there. The loop, test, sleep solution has none of those issues. So if the wait time is known to be short, using sleep in a loop is probably a fine solution. Especially if you can sleep for a second or more between tests. If you can, then don't bother with mutexes and conditions. If the sleep time is short, like 1ms and the wait time is long, like minutes or hours, then you will end up wasting some resources by continually waking up and going back to sleep. You have to judge.

Also be aware that sometimes the kernel will try to wake the waiter thread immediately and other times there will be a delay. If the thread wakes too soon, it will wake while the mutex is locked and immediately go back to sleep until the mutex unlocks. If that becomes a problem, signal the condition this way:

pthread_mutex_lock(&mut);
/* modify x and y */
if (x > y) {
    pthread_mutex_unlock(&mut);
    pthread_cond_broadcast(&cond);
} else
    pthread_mutex_unlock(&mut);

Thanks go to user576875, who's code samples I copied.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM