0

I am trying to create a multi-threaded app in C. At some point the program waits when trying to acquire lock on mutexQueue. but i don't know why. This happens after recreation of the mutex.

for(int i = 80; i<= 8080; i++)
{
    pthread_mutex_init(&mutexQueue,NULL);
    ...
    pthread_mutex_lock(&mutexQueue); <= here it waits forever, after the first iteration (when i=81)
    ...
    pthread_mutex_destroy(&mutexQueue);
}

First time it passes after pthread_mutex_lock therefore it can acquire lock, second time not.

Is there a problem to destroy the mutex and then re-init it after?

Full program execution in real time : https://onlinegdb.com/T5kzCaFUA

EDIT: as @John Carter suggested and reading current pthread documentation (https://pubs.opengroup.org/onlinepubs/007904875/functions/pthread_mutex_destroy.html) it writes :

In cases where default mutex attributes are appropriate, the macro PTHREAD_MUTEX_INITIALIZER can be used to initialize mutexes that are statically allocated. The effect shall be equivalent to dynamic initialization by a call to pthread_mutex_init() with parameter attr specified as NULL, except that no error checks are performed.

i also get the __pthread_mutex_cond_lock_adjust: Assertion (mutex->__data.__kind & 128) == 0' failed. error sometimes, after a long run.

So the error should be somewhere around here, still searching for it.

Thank you.

Daniel Walker
  • 6,380
  • 5
  • 22
  • 45
maxsand
  • 9
  • 3
  • 1
    If this loop is running on multiple threads, this is a recipe for a race condition in multiple ways, and at least one potential UB invocation. Whatever problem this is trying to solve, this isn't the way to do it. – WhozCraig Dec 06 '22 at 16:50
  • 1
    You seem to fundamentally misunderstand the purpose of a mutex in multithreaded applications. A mutex is meant to be an object shared by a group of threads or processes that gets the OS's help to schedule them such that they do not attempt to write shared data while another is attempting to read/write that same data. Creating and destroying mutexes in a loop makes no sense unless the data it's protecting is being created and destroyed at the same speed, and even then, why wouldn't you just reuse the mutex? – Willis Hershey Dec 06 '22 at 18:46
  • I think it might be more productive for you to amend the question with the problem you are trying to solve in a general sense, and then a summary of solution to date (not necessarily source code). – John Carter Dec 06 '22 at 19:38

3 Answers3

2

Are you unlocking the mutex? Destroying a locked mutex results in undefined behaviour:

The pthread_mutex_destroy() function shall destroy the mutex object referenced by mutex; the mutex object becomes, in effect, uninitialized. An implementation may cause pthread_mutex_destroy() to set the object referenced by mutex to an invalid value. A destroyed mutex object can be reinitialized using pthread_mutex_init(); the results of otherwise referencing the object after it has been destroyed are undefined.

phread_mutex_destroy

John Carter
  • 6,752
  • 2
  • 32
  • 53
  • i don't know if I destroy a locked `mutex`, but i do it after `pthread_cancel(threads[iThreads])` on all threads and i recreate it later at the next iteration thus shouldn't be a problem. – maxsand Dec 06 '22 at 16:38
  • 1
    *but i do it after `pthread_cancel(threads[iThreads])` on all threads and i recreate it later at the next iteration thus shouldn't be a problem* [Oh heck **NO**](https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/pthread_mutex_destroy.html): "Attempting to destroy a locked mutex, or a mutex that another thread is attempting to lock, or a mutex that is being used in a pthread_cond_timedwait() or pthread_cond_wait() call by another thread, **results in undefined behavior.**" Cancelling a thread does not unlock a mutex. It's not even guaranteed to do anything to the thread. – Andrew Henle Dec 06 '22 at 16:45
  • 1
    First of all, thank you for your answers, seems is not that simple as i thought. Ok, i destroy the `mutexQueue` and `condQueue` indeed, but i do reinitialize them as well, i don't see where is the problem. I have read better the documentation that i should instead initialize them without passing `NULL` at attributes, like here : https://pastebin.com/bEmTSLYQ ... am I right? – maxsand Dec 06 '22 at 18:38
2

Is there a problem to destroy the mutex and then re-init it after?

If something might still be using it, yes.

The code you showed is crazy: a shared queue's mutex should live as long as the queue it protects.

Further, the code you show acquires a lock and never unlocks. That doesn't make much sense either.

Useless
  • 64,155
  • 6
  • 88
  • 132
  • I never believed that is a problem as long as you re-create it. It is unlocking at line 101 `pthread_mutex_unlock(&mutexQueue);` – maxsand Dec 06 '22 at 18:42
  • "The code you showed is crazy: a shared queue's mutex should live as long as the queue it protects." - and is not protecting it? I want to keep 100 threads open at any time. That program basically reads from a txt file in real time data then executes operations as fast as it can, kinda like in a producer-consumer threaded scenario, only this time, consumer is divided in 100 threads so it can process data faster. – maxsand Dec 06 '22 at 18:44
  • The queue has to live longer than the threads, right? Well, the mutex should live as long as the queue does. It can't protect access to the shared state (the queue) if it keeps getting destroyed. I think you're confusing the lifetime of the mutex with the lifetime of a lock. – Useless Dec 06 '22 at 20:31
  • "I never believed that is a problem" says the person having a problem and arguing with all the people telling them exactly where it is. Why don't you at least _try_ not destroying your synchronization primitives while they're still in use and see if it makes a difference? – Useless Dec 06 '22 at 20:35
  • I am confused by the fact that i don't understand why first iteration works, the second iteration crashes ... i managed to do some tests and i came up with this : https://pastebin.com/bEmTSLYQ ... is this the right way? i tested and is not crashing anymore, but i fully don't understand why i must put manual sleeps before closing threads and destroying the mutex. Thank you for your help btw. – maxsand Dec 06 '22 at 22:04
  • If adding a sleep appears to fix your problem, you have a concurrency error. Properly-synchronized code must work with any possible scheduler behaviour, not depend on lucky timing. If you can deal with translating from C++, [this](https://stackoverflow.com/a/9396587/212858) answer shows roughly what a synchronized queue should look like. – Useless Dec 06 '22 at 23:37
1

I don't know exactly what is your problem really is, but I think you have some misunderstanding with mutex and threads so ill explain to you some basic knowledge about mutex.

A mutex, in its most fundamental form, is just an integer in memory. This integer can have a few different values depending on the state of the mutex. When we speak of mutexes, we also need to speak about the locking operations. The integer in memory is not intriguing, but the operations around it are.

There are two fundamental operations which a mutex must provide:

lock
unlock

A thread wishing to use the mutex, must first call lock, then eventually call unlock to release it

so as I see in your code:

    for(int i = 80; i<= 8080; i++)
    {
        pthread_mutex_init(&mutexQueue,NULL);
        ...
        pthread_mutex_lock(&mutexQueue); //here you lock 'mutexQueue' so 'mutexQueue' need
                                         //to be unlocked so it can pass again the second
                                        //time, otherwise it gonna stop here forever.
        ...
        pthread_mutex_destroy(&mutexQueue);
    }

where you declare pthread_mutex_lock(&mutexQueue); normally your code must wait here forever until pthread_mutex_unlock(&mutexQueue); is called in the other tread then that thread can pass and lock the mutex again for the other treads and so on. You can check that website have some good information about threads https://mortoray.com/how-does-a-mutex-work-what-does-it-cost/ for me, I worked on a project called dining_philosopher_problem and it help me a lot to discover threads/mutex/sharing_memorie/process/semaphore/... you can check it here https://github.com/mittous/philosopher

  • I always call `pthread_mutex_unlock(&mutexQueue);` ... look at my code and real time execution when you have time please, you will understand better – maxsand Dec 07 '22 at 22:58