19

I need to see if a mutex is locked or unlocked in an if statement so I check it like this...

if(mutex[id] != 2){
    /* do stuff */
}

but when I check it gcc gives me the following error:

error: invalid operands to binary != (have 'ptherad_mutex_t' and 'int')

So how can I check to see if the mutex is locked or not?

EDIT:

A key component to my problem is that my threads (by design) lock themselves right AFTER passing control to another thread. So when thread A passes control to thread B thread A is locked, thread B does some stuff, then when thread B is done it will unlock thread A.

The problem with this is that if thread B attempts to unlock thread A and thread A has not yet completed locking itself then the call to unlock is lost and thread A remains locked which causes a dead lock.

UPDATE:

I remade my program taking caf's suggestion but I am still running into problems. I have molded my program into the structure caf provided the best I can but I cannot even tell what is causing the dead lock now... I have created a new question here seeking help with my code.

Below is a runnable version of caf's suggestion. I made a small reordering in the function for thread a, without which both thread a and thread b would have been locked upon their creation, waiting for a condition that could never change.

#include <pthread.h>

int run_a = 0;
pthread_mutex_t lock_a = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_a = PTHREAD_COND_INITIALIZER;

int run_b = 0;
pthread_mutex_t lock_b = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_b = PTHREAD_COND_INITIALIZER;

void *a(void *);
void *b(void *);

int main(){
    int status;
    pthread_t thread_a;
    pthread_t thread_b;

    pthread_create(&thread_a, NULL, a, (void *)0);
    pthread_create(&thread_b, NULL, b, (void *)0);

    pthread_join(thread_a, (void **)&status);
    pthread_join(thread_b, (void **)&status);

}

/* thread A */
void *a(void *i){
    while (1) {
        printf("thread A is running\n");
        sleep(1);

        /* unlock thread B */
        pthread_mutex_lock(&lock_b);
            run_b = 1;
            pthread_cond_signal(&cond_b);
        pthread_mutex_unlock(&lock_b);

        /* wait for thread A to be runnable */
        pthread_mutex_lock(&lock_a);
            while (!run_a)
                pthread_cond_wait(&cond_a, &lock_a);
            run_a = 0;
        pthread_mutex_unlock(&lock_a);      
    }
}

/* thread B */
void *b(void *i){
    while (1) {
        /* wait for thread B to be runnable */
        pthread_mutex_lock(&lock_b);
            while (!run_b)
                pthread_cond_wait(&cond_b, &lock_b);
            run_b = 0;
        pthread_mutex_unlock(&lock_b);

        printf("thread B is running\n");
        sleep(1);

        /* unlock thread A */
        pthread_mutex_lock(&lock_a);
            run_a = 1;
            pthread_cond_signal(&cond_a);
        pthread_mutex_unlock(&lock_a);
    }
}
Community
  • 1
  • 1
ubiquibacon
  • 10,451
  • 28
  • 109
  • 179
  • 1
    A quick note, mutexes must be unlocked by the thread that locked them. If you want a locking construct that can be locked by one thread and unlocked by another, you must use semaphores (or build your own semaphore as shown in the above example). Really ugly synchronization bugs can crop up if one thread locks a mutx and another releases it – Cort Ammon Sep 04 '13 at 03:10

3 Answers3

32

You can use pthread_mutex_trylock. If that succeeds, the mutex was unclaimed and you now own it (so you should release it and return "unheld", in your case). Otherwise, someone is holding it.

I have to stress though that "check to see if a mutex is unclaimed" is a very bad idea. There are inherent race conditions in this kind of thinking. If such a function tells you at time t that the lock is unheld, that says absolutely nothing about whether or not some other thread acquired the lock at t+1.

In case this is better illustrated with a code example, consider:

bool held = is_lock_held();

if (!held)
{
  // What exactly can you conclude here?  Pretty much nothing.
  // It was unheld at some point in the past but it might be held
  // by the time you got to this point, or by the time you do your
  // next instruction...
}
asveikau
  • 39,039
  • 2
  • 53
  • 68
  • @asveikau my problem is that I have a thread (a) that passes control to another thread (b) then locks itself. Once thread `b` is done it unlocks thread `a` then locks itself. The system works great but on rare occasion thread `b` "unlocks" thread `a` before thread `a` locks itself, thus the "unlock" is lost and the program dead locks. I have tried to use `trylock` but not the way you suggested... I will try again. – ubiquibacon Dec 06 '10 at 01:29
  • @typoknig - It sounds like you should consider a simpler synchronization scheme. For example, you could have B signal a semaphore that A waits on. – asveikau Dec 06 '10 at 01:33
  • @asveikau the issue is that thread A has control and must lock itself, and I have no control over how fast it locks itself. B does signal/unlock the semaphore for thread A, when thread B is done, but if thread A has not yet locked itself (and does so after thread B has signaled for the unlock) the thread A will remain locked. – ubiquibacon Dec 06 '10 at 01:39
  • 1
    Is there a reason the threads can't just share one mutex? Thread A releases the mutex, yields the CPU, and then waits on the mutex again. Thread B will be woken up when A releases, will take the mutex, and then there's no notify-before-wait problem. – Anon. Dec 06 '10 at 01:42
  • I have many threads and (like A[10] and B[10]) which are not paired together, but are depended on each other. For instance thread A[1] might be dependent on thread B[5] this loop, but the next loop it might be dependent on thread B[7] or some other thread. – ubiquibacon Dec 06 '10 at 01:48
  • @typoknig: So have say, all the A threads owning the mutexes, and the B threads using the mutex owned by their corresponding A thread? – Anon. Dec 06 '10 at 02:13
  • Checking whether the mutex is locked or not can be a great aid in _debugging_ your locking scheme. So, it would be helpful if something like a `pthread_mutex_islocked()` primitive existed. – nccc Aug 29 '12 at 01:38
  • With only 2 threads its not a problem. Only 1 can hold lock at a time, so if lock is free, than it's definitely won't be locked in t+1. – ScienceDiscoverer Apr 02 '21 at 12:26
26

Mutexes are not the right primitive for the scheme that you want to implement. You should be using condition variables:

int run_thread_a = 0;
pthread_mutex_t run_lock_a = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t run_cond_a = PTHREAD_COND_INITIALIZER;

int run_thread_b = 0;
pthread_mutex_t run_lock_b = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t run_cond_b = PTHREAD_COND_INITIALIZER;

/* thread A */
while (1) {
    /* Wait for Thread A to be runnable */
    pthread_mutex_lock(&run_lock_a);
    while (!run_thread_a)
        pthread_cond_wait(&run_cond_a, &run_lock_a);
    run_thread_a = 0;
    pthread_mutex_unlock(&run_lock_a);

    /* Do some work */

    /* Now wake thread B */
    pthread_mutex_lock(&run_lock_b);
    run_thread_b = 1;
    pthread_cond_signal(&run_cond_b);
    pthread_mutex_unlock(&run_lock_b);
}

/* thread B */
while (1) {
    /* Wait for Thread B to be runnable */
    pthread_mutex_lock(&run_lock_b);
    while (!run_thread_b)
        pthread_cond_wait(&run_cond_b, &run_lock_b);
    run_thread_b = 0;
    pthread_mutex_unlock(&run_lock_b);

    /* Do some work */

    /* Now wake thread A */
    pthread_mutex_lock(&run_lock_a);
    run_thread_a = 1;
    pthread_cond_signal(&run_cond_a);
    pthread_mutex_unlock(&run_lock_a);
}

Each thread will block in pthread_cond_wait() until the other thread signals it to wake up. This will not deadlock.

It can easily be extended to many threads, by allocating one int, pthread_cond_t and pthread_mutex_t per thread.

caf
  • 233,326
  • 40
  • 323
  • 462
  • @caf I had originally tried using a condition, but my threads need to run concurrently, and unless I want to make a condition for each one (an array of conditions will not work because it would be blocked each time it was accessed by any thread, thus eliminating the desired concurrency) I do not see how I can make this work. – ubiquibacon Dec 06 '10 at 06:51
  • @typoknig: An array of conditions is exactly what you need. It will not be "blocked each time it was accessed by any thread". Each condition variable is independent - it does not matter whether you keep them in an array or in separate named globals. – caf Dec 06 '10 at 12:07
  • @caf I have updated my question and added my code, perhaps you might take a look at it. I know the structure you have suggested is correct, but I still cannot get it to work right (see updated question). The code I have posted is completely rewritten from when I asked my question (now using condition). – ubiquibacon Dec 07 '10 at 05:03
  • @typoknig: I'll have a look, but you may be better off to post the new code as a new question. – caf Dec 07 '10 at 05:29
  • @caf I made a new question as you suggested, thanks for your help. – ubiquibacon Dec 07 '10 at 21:30
  • @typoknig: No worries, I have put a lengthy answer there. – caf Dec 08 '10 at 01:40
3

You can't compare a pthread_mutex_t with a int.

You can use

int pthread_mutex_trylock(pthread_mutex_t *mutex);

to check that.

Mojtaba Ahmadi
  • 1,044
  • 19
  • 38
Huang F. Lei
  • 1,835
  • 15
  • 23