Pthread: lock PTHREAD_MUTEX_ERRORCHECK mutex from non-owner thread - c

classical question please;
I didn't find confirmation from code;
C language.
I'm running the below code on Windows.
/* This is an implementation of the threads API of POSIX 1003.1-2001.*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
//equivalent to PTHREAD_MUTEX_ERRORCHECK
void* thread_function(void *args)
{
int rc;
rc = pthread_mutex_unlock( & mutex );
printf( "[thread_function] pthread_mutex_unlock rc: %d \n", rc);
return 0;
}
int main(int argc, char* argv[])
{
int rc;
pthread_t id;
pthread_mutex_lock( &mutex );
rc = pthread_create(&id, NULL, thread_function, NULL);
pthread_join(id, NULL);
printf( "[main] completed\n");
}
rc = pthread_mutex_unlock( & mutex ); - returns rc equal to 1 which is as expected.
but when I change the code to rc = pthread_mutex_lock( & mutex ); - the error does not occur.
But in many Pthread API doc it is mentioned that:
"If the mutex type is PTHREAD_MUTEX_ERRORCHECK, then error checking shall be provided. If a thread attempts to relock a mutex that it has already locked, an error shall be returned."
But it is not returned for me, and the question why?
The only guess I have - it depends on PThread realization which I'm using.
And it also may depend on OS; i.e. same code and the same version of Pthread lib will give different result on Linux.
Can anyone please clarify?
Thanks!

When a thread tries to lock a mutex locked by another thread, it blocks. This is of course the whole point: it would be useless if it were an error. The error checking is for programs where a thread might try to lock a mutex it has already locked. That usually results from a logic bug, although one could simulate a recursive mutex with it or perhaps use the locked state of the mutex as some sort of memory.

Generally, when you tried to lock mutex(Default Type) second time in the same thread your code has been blocked. To prevent this blocking situation, error checking mutex is used.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#define IN_MAIN ""
#define IN_THREAD "\t"
#define START_MAIN printf(IN_MAIN "\n-- Main Start -- \n");
#define END_MAIN printf(IN_MAIN "-- Main End -- \n\n"); \
exit(EXIT_SUCCESS);
#define ERROR_HANDLER(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void * thread_routine(void * arg)
{
printf(IN_THREAD "-- Thread Start -- \n");
int ret;
pthread_mutex_lock(&mutex);
printf(IN_THREAD " Thread acquire lock for first time \n");
ret = pthread_mutex_lock(&mutex);
if(ret)
{
switch(ret)
{
case EDEADLK:
printf(IN_THREAD " A deadlock condition was detected \n");
break;
default:
ERROR_HANDLER(ret, "pthread_mutex_lock");
}
}
sleep(1);
ret = pthread_mutex_unlock(&mutex);
printf(IN_THREAD " Thread release lock first time -- %d \n", ret);
sleep(1);
ret = pthread_mutex_unlock(&mutex);
printf(IN_THREAD " Thread release lock second time -- %d \n", ret);
printf(IN_THREAD "-- Thread End --\n");
pthread_exit(NULL);
}
int main(int argc, char ** argv)
{
START_MAIN;
pthread_t thread_id;
pthread_mutexattr_t mutex_attr;
int mutex_type, ret=0;
pthread_mutexattr_init(&mutex_attr);
ret = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
if(ret)
ERROR_HANDLER(ret, "pthread_mutexattr_settype");
pthread_mutex_init(&mutex, &mutex_attr);
pthread_create(&thread_id, NULL, thread_routine, NULL);
pthread_join(thread_id, NULL);
END_MAIN;
}
Consider above example, when you execute the above code, it print "A deadlock condition was detected". This is because of the type of mutex is error check.
Now comment the line
ret = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
and execute the code. You'll notice your code is blocked after it print "Thread acquire lock for first time".

One of the mistakes in the Posix spec is the notion of "default" mutex type -- which is implementation dependent. Meaning the the semantics of a "default" mutex is any ones guess. Confusing? You bet.
My advice is to never use "default" for mutex type if you care about portability at all.

Related

sem_init and pthread_mutex_init

I was writing 2 similar codes for printing odd and even numbers from given number set using mutex lock and semaphore. Both of the codes works fine.
But, while using mutex lock, even if I wont declare the pthread_mutex_init function, still the program executes with no issues. But that's not the case with semaphore. For this case, I have to declare sem_init in main() else the program execution gets stuck in sem_wait() (found after debugging).
So, how in the case of mutex lock, even without declaring init(), the program executes?
For reference, I am attaching the semaphore code.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
sem_t mutex;
pthread_t tid[2];
unsigned int shared_data[] = {23,45,67,44,56,78,91,102};
unsigned int rc;
int len=(sizeof(shared_data)/sizeof(shared_data[0]));
int i=0;
void *even(void *arg) {
rc = sem_wait(&mutex);
int temp = rc;
if(rc)
printf("Semaphore failed\n");
do{
if(shared_data[i] %2 == 0) {
printf("Even: %d\n",shared_data[i]);
i++;
}
else
rc = sem_post(&mutex);
}while(i<len);
}
void *odd(void *arg) {
rc = sem_wait(&mutex);
if(rc)
printf("Semaphore failed\n");
do {
if(shared_data[i] %2 != 0) {
printf("Odd: %d\n",shared_data[i]);
i++;
}
else
rc = sem_post(&mutex);
}while(i<len);
}
int main() {
sem_init(&mutex, 0,1);
pthread_create(&tid[0], 0, &even, 0);
pthread_create(&tid[1], 0, &odd, 0);
pthread_join(tid[0],NULL);
pthread_join(tid[1],NULL);
sem_destroy(&mutex);
return 0;
}
EDIT: Attaching the mutex lock code as well.
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
pthread_t tid[2];
unsigned int shared_data []= {23,45,67,44,56,78,91,102};
pthread_mutex_t mutex;
unsigned int rc;
int len=(sizeof(shared_data)/sizeof(shared_data[0]));
int i=0;
void* PrintEvenNos(void *ptr)
{
rc = pthread_mutex_lock(&mutex);
if(rc)
printf("Mutex lock has failed\n");
do
{
if(shared_data[i]%2 == 0)
{
printf("Even:%d\n",shared_data[i]);
i++;
} else {
rc=pthread_mutex_unlock(&mutex);
}
} while(i<len);
}
void* PrintOddNos(void* ptr1)
{
rc = pthread_mutex_lock(&mutex);
if(rc)
printf("Mutex lock has failed\n");
do
{
if(shared_data[i]%2 != 0)
{
printf("Odd:%d\n",shared_data[i]);
i++;
} else {
rc=pthread_mutex_unlock(&mutex);
}
} while(i<len);
}
void main(void)
{
pthread_create(&tid[0],0,PrintEvenNos,0);
pthread_create(&tid[1],0,PrintOddNos,0);
pthread_join(tid[0],NULL);
pthread_join(tid[1],NULL);
}
So, how in the case of mutex lock, even without declaring init(), the program executes?
This is undefined behavior, so there is no proper result. Per POSIX pthread_mutex_lock():
If mutex does not refer to an initialized mutex object, the behavior of pthread_mutex_lock(), pthread_mutex_trylock(), and pthread_mutex_unlock() is undefined.
"Appears to work" is one possible result of undefined behavior.
You have sem_init call for sem_t mutex;.
But pthread_mutex_init call is missing for pthread_mutex_t mutex;.
Both of the codes works fine.
No they don't; but first:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
Is how you should have initialized your mutex. On your system, this value might be zero, which would be equivalent to what you have. Either way, the problem is your program is broken.
One of your threads (even, odd) acquires a lock. In the case of even, when i is 0,1,2,5 or 6; you unlock it, which would permit odd() to proceed. In the case of odd, when i is 3,4,5 or 7, you unlock it, which would permit even() to proceed. So in your logic, the lock does nothing at all.
Also, semaphores are counters; so when you release it 5 times, you are permitting the next 5 sem_waits to proceed. Simple mutexes are gates, so only the first unlock has any effect, the subsequent 4 are errors. You don't check the error status of the unlock, which is typically the one that uncovers logic errors.
fwiw, on macos, the pthread_mutex_lock()'s both report an error.

C Pthread: Running only 10 threads simultaneously (what is the problem here)

So I'm very new to the whole concept of pthread in C but please hear me out. I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t endCond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t startCond = PTHREAD_COND_INITIALIZER;
void * threadThingy(void * n){
pthread_cond_wait(&startCond, &mutex);
printf("%d: RAND: %d\n", *((int*)n), rand());
//Lock mutex before broadcasting to main thread
pthread_mutex_lock(&mutex);
pthread_cond_broadcast(&endCond);
pthread_mutex_unlock(&mutex);
free(n);
fflush(stdout);
return 0;
}
int main(void){
printf("Starting\n");
pthread_t threads[100];
int i = 0;
while(i < 10){
int *arg = malloc(sizeof(int));
*arg = i;
pthread_create(&threads[i], NULL, threadThingy, arg);
i++;
}
pthread_mutex_lock(&mutex);
pthread_cond_broadcast(&startCond);
int finished = 0;
while(finished <= 100){
pthread_cond_wait(&endCond, &mutex);
//Lock mutex so no other requests can come in
pthread_mutex_lock(&mutex);
finished++;
int *arg = malloc(sizeof(int));
*arg = 11;
pthread_create(threads[i], NULL, threadThingy, arg);
i++;
pthread_cond_broadcast(&startCond);
pthread_mutex_unlock(&mutex);
}
printf("Stopping\n");
sleep(1000);
}
The whole goal is to run (only) 10 threads simultaneously of the 100. My idea was to start 10 threads, than wait until one is finished and start another one. So I let the program wait until a thread returns, then I start a new one so the thread that just returned gets replaced. What have I missed? Because now I only get this as an output:
Starting
0: RAND: 1804289383
As mentioned by Lavigne958, in function threadThingy() there is deadlock caused by pthread_cond_wait() as it will acquire the lock. Again, you are trying to lock it in next line. This is causing deadlock.
There are a few things need to check:
You need to lock the mutex before calling pthread_cond_wait().
If you solve the above issue, using multiple condition variable with the same mutex may cause further deadlock.
If you are not joining the threads, it will be better to create detached threads using PTHREAD_CREATE_DETACHED attribute.
The problem of N number of threads running simultaneously can be solved with one semaphore OR one condition variable(and one mutex). Example with semaphore is given below.
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
sem_t mysem;
#define NUM_CONCURRENT_THREADS 4
#define MAX_THREADS 40
void *thread(void *arg)
{
printf("Thread id %ld: started\n", pthread_self());
sleep(5); // Do some work
printf("Thread id %ld: Exiting\n", pthread_self());
sem_post(&mysem);
return NULL;
}
int main()
{
pthread_t t[MAX_THREADS];
pthread_attr_t attr;
int rc, i = 0;
sem_init(&mysem, 0, NUM_CONCURRENT_THREADS);
rc = pthread_attr_init(&attr);
rc = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
printf("\nParent begin\n");
while(i < MAX_THREADS)
{
sem_wait(&mysem);
pthread_create(&t[i], &attr, thread, NULL);
i++;
}
printf("\nParent end.\n");
sem_destroy(&mysem);
return 0;
}
Please check blog Tech Easy for more information on threads.
in the function that your threads run, you start by waiting on a condition but you forgot to take the mutex before. So you first must take the mutex before waiting on the condition.
you have what we call a deadlock.
What happens is:
the first thread wakes up (the pthread_con_wait function acquires the lock for you already)
then you try to acquire the lock again => deadlock because you already own the lock so you kinda deadlock yourself.

pthread_mutex_timedlock() exiting prematurely without waiting for timeout

I want to protect a function from multithreaded access. For that purpose I am using a pthread_mutex_t mutex. I try to lock it in the beginning of a function, then execute the function, then release it again. If the mutex is in use it should wait for at maximum 60 seconds for it to be come available. If after that it is still not available, the function should fail.
The problem I'm having is it that pthread_mutex_timedlock seems to completely ignore the timeout value I'm giving it. Although I specify a timeout of 60 seconds, if the lock is taken, the function returns immediately with the error code ETIMEDOUT -- without actually waiting.
Here is a minimal example which reproduces the problem. In this case it does not matter whether I'm using recursive or non-recursive mutexes, since I'm not trying to lock them multiple times from the same thread.
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stddef.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <pthread.h>
pthread_mutex_t lock; /* exclusive lock */
//do some work to keep the processor busy..
int wut() {
int x = 0;
for(int i=0; i < 1024*1024*1024; i++)
x += 1;
return x;
}
void InitMutex(){
/*pthread_mutexattr_t Attr;
pthread_mutexattr_init(&Attr);
pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&lock, &Attr);*/
pthread_mutex_init(&lock, NULL);
}
//lock mutex, wait at maximum 60 seconds, return sucesss
int LockMutex() {
struct timespec timeoutTime;
timeoutTime.tv_nsec = 0;
timeoutTime.tv_sec = 60;
printf("Nanoseconds: %lu, seconds %lu\n", timeoutTime.tv_nsec, timeoutTime.tv_sec);
int retVal = pthread_mutex_timedlock(&lock, &timeoutTime);
printf("pthread_mutex_timedlock(): %d\n", retVal);
if(retVal != 0) {
const char* errVal = NULL;
switch(retVal) {
case EINVAL: errVal = "EINVAL"; break;
case EAGAIN: errVal = "EAGAIN"; break;
case ETIMEDOUT: errVal = "ETIMEDOUT"; break;
case EDEADLK: errVal = "EDEADLK"; break;
default: errVal = "unknown.."; break;
}
printf("Error taking lock in thread %lu: %s (%s)\n", pthread_self(), errVal , strerror(retVal));
}
return retVal == 0; //indicate success/failure
}
void UnlockMutex() {
pthread_mutex_unlock(&lock);
}
void TestLockNative() {
uint64_t thread_id = pthread_self();
printf("Trying to take lock in thread %lu.\n", thread_id);
int ret = LockMutex();
printf("Got lock in thread %lu. sucess=%d\n", thread_id, ret);
wut();
printf("Giving up lock now from thread %lu.\n", thread_id);
UnlockMutex();
}
void* test_thread(void* arg) {
//TestLock();
TestLockNative();
return NULL;
}
int main() {
InitMutex();
//create two threads which will try to access the protected function at once
pthread_t t1, t2;
pthread_create(&t1, NULL, &test_thread, NULL);
pthread_create(&t2, NULL, &test_thread, NULL);
//wait for threads to end
pthread_join(t1, NULL);
pthread_join(t2, NULL);
return 0;
}
The output of the program is e.g.:
Trying to take lock in thread 139845914396416.
Nanoseconds: 0, seconds 6000
pthread_mutex_timedlock(): 0
Got lock in thread 139845914396416. sucess=1
Trying to take lock in thread 139845906003712.
Nanoseconds: 0, seconds 6000
pthread_mutex_timedlock(): 110
Error taking lock in thread 139845906003712: ETIMEDOUT (Connection timed out) [<-- this occurs immediately, not after 60 seconds]
Got lock in thread 139845906003712. sucess=0
Giving up lock now from thread 139845906003712.
Compilation with gcc -o test test.c -lpthread should work.
So, does anyone know what's going on here and why pthread_mutex_timedlock() ignores my timeout value? It does not behave the way it is documented at all.
I'm using a Ubuntu 16.04.2 LTS system, compiling with gcc.
The manual page for pthread_mutex_timedlock says:
The timeout shall expire when the absolute time specified by abstime passes, as measured
by the clock on which timeouts are based
Therefore, use real time to specify your timeout value:
int LockMutex() {
struct timespec timeoutTime;
clock_gettime(CLOCK_REALTIME, &timeoutTime);
timeoutTime.tv_sec += 60;
int retVal = pthread_mutex_timedlock(&lock, &timeoutTime);
....

pthread_cond_timedwait call is not working with mutex locking mechanism

I have a logging application. In which after specific time (user configureable time) i need to close the current log file and and create a new log file and log the data.
There are 2 critical sections of code in my program.
Writing the data to file (in while(1))
Close and open the new file
Whenever time expires i need to stop the logging to the file and close it & open the new log file and start logging.
For this purpose i have created a sample application exactly same as my application, but instead of file operation here am doing with printf.
I am using pthread_cond_timedwait call to handle the timer related operation. Here is my sample code -
#include <stdio.h>
#include <sys/time.h>
#include <errno.h>
#include <pthread.h>
/* For safe condition variable usage, must use a boolean predicate and */
/* a mutex with the condition. */
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
#define WAIT_TIME_SECONDS 10
void *threadfunc(void *parm)
{
int rc;
struct timespec abstime;
struct timeval now;
/* Usually worker threads will loop on these operations */
while (1) {
rc = gettimeofday(&now, NULL);
/* Convert from timeval to timespec */
abstime.tv_sec = now.tv_sec + WAIT_TIME_SECONDS;
abstime.tv_nsec = (now.tv_usec + 1000UL * WAIT_TIME_SECONDS) * 1000UL;
abstime.tv_sec += abstime.tv_nsec / (1000 * 1000 * 1000);
abstime.tv_nsec %= (1000 * 1000 * 1000);
printf("Thread blocked\n");
pthread_mutex_lock(&mutex);
rc = pthread_cond_timedwait(&cond, &mutex, &abstime);
pthread_mutex_unlock(&mutex);
printf("Wait timed out!\n");
/* critical section of code */
pthread_mutex_lock(&lock);
printf("Thread consumes work here\n");
pthread_mutex_unlock(&lock);
}
return NULL;
}
int main(int argc, char **argv)
{
int rc=0;
pthread_t threadid;
rc = pthread_create(&threadid, NULL, threadfunc, NULL);
if (rc != 0) {
printf("Thread creation failed err:%d\n", errno);
return -1;
}
while (1) {
/* critical section of code */
sleep(1);
pthread_mutex_lock(&lock);
printf("One work item to give to a thread\n");
pthread_mutex_unlock(&lock);
}
printf("Wait for threads and cleanup\n");
pthread_join(threadid, NULL);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
printf("Main completed\n");
return 0;
}
This code is not working. Whenever pthread_cond_timedwait expires threadfunc function should acquire mutex lock and it needs print the statements. After printing am releasing the mutex. But it is not happening. Control is never transfered from main() to threadfunc. Whats is going wrong here?
But instead of mutex if i use a variable to do the handling of critical section of code am able to do it. Say -
static int stop = 0; // take a global variable
//inside threadfunc
/* critical section of code */
stop = 1; //Replace pthread_mutex_lock with this
printf("Thread consumes work here\n");
stop = 0; //Replace pthread_mutex_unlock with this
//in main()
while (1) {
/* critical section of code */
sleep(1);
if (!stop)
printf("One work item to give to a thread\n");
}
This approach is working fine.
When i am using more then one mutex in my code am not able to implement this. What is the real thing happening behind? Am i missing anything while am using mutex to handle critical section of a code?
Thanks in advance!

printf with pthreads in C

I am working with pthreads right now doing the producer/consumer problem. I am currently just trying to get the producer working and using printf statements to see where my issues are. The problem is the code compiles just fine but when I run it, it doesn't do anything but seems to run just fine. I have tried setting my first line to a printf statement but even that does not print. I have tried using fflush as well and I am running out of ideas. My question why would even the first printf statement get skipped?
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
void *producer();
pthread_mutex_t lock;
pthread_cond_t done, full, empty;
int buffer[10];
int in = 0, out = 0;
int min = 0, max = 0, numOfItems = 0, total = 0;
double avg;
void *producer() {
srand(time(NULL));
int n = rand();
int i;
for(i = 0; i < n; i++)
{
int random = rand();
pthread_mutex_lock(&lock);
buffer[in++] = random;
if(in == 10)
{
pthread_cond_signal(&full);
printf("Buffer full");
pthread_mutex_unlock(&lock);
sleep(1);
}
}
pthread_exit(NULL);
}
void *consumer() {
pthread_exit(NULL);
}
int main(int argc, char *argv[]){
printf("test");
//Create threads and attribute
pthread_t ptid, ctid;
pthread_attr_t attr;
//Initialize conditions and mutex
pthread_cond_init(&full, NULL);
pthread_cond_init(&empty, NULL);
pthread_cond_init(&done, NULL);
pthread_mutex_init(&lock, NULL);
//Create joinable state
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&ptid, &attr,(void *)producer,NULL);
pthread_create(&ctid, &attr,(void *)consumer,NULL);
pthread_join(ptid,NULL);
pthread_join(ctid,NULL);
printf("Program Finished!");
pthread_exit(NULL);
}
man pthread_mutex_init
pthread_mutex_init initializes the mutex object pointed to by mutex
according to the mutex attributes specified in mutexattr. If mutexattr
is NULL, default attributes are used instead.
The LinuxThreads implementation supports only one mutex attributes, the
mutex kind... The kind of a mutex determines whether it can be locked again by
a thread that already owns it. The default kind is fast...
If the mutex is already locked by the calling thread, the behavior of
pthread_mutex_lock depends on the kind of the mutex. If the mutex is of
the fast kind, the calling thread is suspended until the mutex is
unlocked, thus effectively causing the calling thread to deadlock.
That's what happens to your producer: it deadlocks in the call
pthread_mutex_lock(&lock);
- except in the unlikely case n < 2 - thus producing no output.

Resources