0

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);
}
battyman17
  • 65
  • 6
  • 2
    Because your variables are all global they will be *zero initialized*. For a `pthread_mutex_t` that might just happen to be the correct way on your local system, but not for a `sem_t`. Generally, *always* explicitly "initialize" your variables, global or not. – Some programmer dude Mar 05 '20 at 11:42
  • @attyman17 Where is the code using `pthread_mutex_init` who surprises you ? – Landstalker Mar 05 '20 at 11:57
  • @Landstalker I have added it now. – battyman17 Mar 05 '20 at 12:34
  • @battyman17 it works just because the initialization values ​​assigned by your compiler coincide with the values ​​that you would have explicitly assigned with the pthread_mutex_init function. – Landstalker Mar 05 '20 at 13:18
  • @SolomonSlow *programs no longer need to explicitly initialize a staticly allocated `pthread_mutex_t` object.*??? Where? Per [POSIX `pthread_mutex_init()`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html): "In cases where default mutex attributes are appropriate, the macro `PTHREAD_MUTEX_INITIALIZER` can be used to initialize mutexes. 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." – Andrew Henle Mar 05 '20 at 14:15
  • @SolomonSlow I prefer to initialize my variables explicitly. it's more secure. – Landstalker Mar 05 '20 at 14:17
  • Maybe I was misremembering something... Comment retracted. – Solomon Slow Mar 05 '20 at 14:18

3 Answers3

2

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.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
0

You have sem_init call for sem_t mutex;.

But pthread_mutex_init call is missing for pthread_mutex_t mutex;.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • 1
    he was surprised that his program works even without `pthread_mutex_init`. The compiler did this task for him ... The implicit initialization of the compiler coincides with the explicit initialization using `pthread_mutex_init` – Landstalker Mar 05 '20 at 13:22
0

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.

mevets
  • 10,070
  • 1
  • 21
  • 33