1

I am running 1 thread created with pthreads and I'm using a mutex between the thread and my main thread. From what I understand, once a thread is ready to lock a mutex, it will spinlock until its able to lock. But I'm running into an issue where it doesn't spinlock. The pseudo code I have.

Main thread:

//I create thread 1 on this line, then it enters the while loop
while(p.size() > r.size()){
  pthread_mutex_lock(&Mutex);
  //calculations and decrease p.size()
  pthread_mutex_unlock(&Mutex);
}

Thread 1:

//wait 500ms before hitting mutex
pthread_mutex_lock(&Mutex);
//calculations
pthread_mutex_unlock(&Mutex);

The issue I'm running to is that the Thread 1 Mutex never locks until the main thread while loop exits. Thread 1 reaches the mutex lock before the main thread can finish the while loop.

EDIT: If I had a delay of 10ms to the end of my while loop (after the mutex unlocks), then this fixes my problem. But how can I fix the problem without adding a delay of 10ms.

JDoe4444
  • 35
  • 4
  • The C standard doesn't define a `sleep` function, and I believe the Posix `sleep` function takes seconds as the argument. – user3386109 May 09 '18 at 07:09
  • @user3386109 The sleep function is irreverent, just pretend the thread delays before hitting the mutex. – JDoe4444 May 09 '18 at 07:11
  • Getting beyond the potential error in sleep(). In the case of Windows native threads and native mutexes, generally the order of locks acquired is in the order of requests. In other environments, the order of locks granted may not be specified, and it's possible for the same thread to keep acquiring a lock, even when multiple threads are pending trying to get the lock. In some cases, this occurs because the thread doing a loop with unlock() lock() sequence is the currently actively running thread, so it acquires the mutex again and no context switch occurs. – rcgldr May 09 '18 at 07:16
  • Probably that much amount of time your system needs to start and schedule the new thread into execution – Pras May 09 '18 at 07:16
  • @rcgldr Okay, this makes sense. Do you know if the pthread_cond_wait() will fix my issue? – JDoe4444 May 09 '18 at 07:18
  • 1
    not really clear what is the issue. If thread 1 should finish before the main enters the loop, then why are you doing the calculations in a seperate thread? – 463035818_is_not_an_ai May 09 '18 at 07:18
  • @Pras, you and rcgldr said about the same thing which makes total sense, do you know if the pthread_cond_wait() will fix this issue? – JDoe4444 May 09 '18 at 07:19
  • If you want to sync threads use condition variable. – Sumit Jha May 09 '18 at 07:19
  • @JDoe4444 - I'm not sure how pthreads are implemented in Windows. One option here is to use one mutex per thread, if the environment supports that. One semaphore per thread would make more sense, but some systems like Linux, don't have native support for semaphores, and some commercial multi-threaded or multi-processing applications install drivers to do the spinlocks in order to balance loads between threads or processes. – rcgldr May 09 '18 at 07:22
  • @JDoe4444 - Windows and some other operating systems use queues or the equivalent for requests for native resources (mutex, semaphore, ...), which guarantees some type of ordering. I don't know why Linux doesn't include such a feature. – rcgldr May 09 '18 at 07:26
  • @JDoe4444 - as suggested by Sumit Jha, you can use condition variables to emulate semaphores, but you have to deal with [spurious wakeups](https://en.wikipedia.org/wiki/Spurious_wakeup), where thread is made runnable without the resource being ready. – rcgldr May 09 '18 at 07:30
  • @JDoe4444 Hey you should go ahead and ask a new question for your EDIT question. IMO it's a good question. You're basically asking how you to achieve fairness in pthreads. Please include information for what OS, what CPU, what compiler, and whether or not you are allowed to use the C++11 standard (or higher) – Humphrey Winnebago May 10 '18 at 08:11
  • OT: In case `p.size()` is read/written by the other thread as well, the code might race and invoke UB as here `while(p.size() > r.size())` the access to `p.size()` is **not** protected. – alk May 10 '18 at 14:34

1 Answers1

2

Your main thread is unlocking the mutex and then immediately locking it again. Try introducing a delay in your main loop (for testing purposes) to see if this is the issue.

Check out the answer to this question: pthreads: thread starvation caused by quick re-locking

Humphrey Winnebago
  • 1,512
  • 8
  • 15
  • Thank you so much, I didn't know that the OS would be running threads that quickly to skip over other threads. I need to use a conditional variable. Thank you and to the others in the comments who helped me out with this. Thank you. – JDoe4444 May 09 '18 at 07:22
  • @JDoe4444 - its' an OS dependent issue. As commented above, in the case of Windows (and other operating systems) using native synchronization interface, internal queues (or the equivalent) are used to order requests, eliminating issues like this or having to deal with spurious wakeups. Quick relocking isn't an issue for these operating systems because of the queuing forcing context switches as needed to preserve the order of requests. – rcgldr May 09 '18 at 07:33
  • @JDoe4444, you assumed that the mutex is implemented as a spin-lock, but that is not practical for a general-purpose mutex implementation running on a multi-tasking OS. If your `thread1` is blocked for any significant length of time then the OS will put it to sleep. Then, when the main thread releases the mutex and immediately tries to lock it again, you've got a race between a sleeping thread and one that is already in memory and running. Unless it's a so-called "fair" mutex, the already-running thread will always win that race. – Solomon Slow May 09 '18 at 13:29