Search code examples
cmultithreadingsemaphorevolatile

C multithreading : Race condition scenarios


In the below code I'm just trying to see if I would be able to insert an element into an array , from each thread. It is working as expected. But then I wonder , under what circumstances there can be a race condition here. Do I really need volatile here, or semaphores? I tried removing semaphores and volatile keywords, still it works. I want to induce and see a race condition scenario as well here. On the same lines, Can I create a node from each thread and put all nodes into a linked list? These are all imaginary scenarios..!!

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include "small_appl.h"

void * thread_func(void * arg);

int itr=0;
volatile int idx=0; //array index variable
sem_t sem1;
int arr_th[5];      //array where each thread will insert an element

int func_pointed(int a,int num_t)
{
    pthread_t arr_thr[num_t];
    int iter;
     //create threads
     for(iter=0;iter<num_t;iter++)
     {
        pthread_create(&arr_thr[iter],NULL,thread_func,(void *)a);
     }

     for (iter=0;iter<num_t;iter++)
     {
         pthread_join(arr_thr[iter],NULL);
     }
}

int main(void)
{
    int ip1=5,ip2=10,rev;

    rev=sem_init(&sem1,0,0);
    s_type dev_s={
                    .f_ptr=func_pointed,
                    .str="Diwakar",
                    .val=5
                 };

    //initialize semaphore to 1
    sem_post(&sem1);    

    func_aux(ip1,dev_s);

    for(rev=0;rev<5;rev++)
    {
    printf("array : %d    ",arr_th[rev]);
    }

}

void * thread_func(void * arg)
{
    sem_wait(&sem1);
    printf("Got sema\n");
    arr_th[idx]=itr;
    idx++; itr++;
    printf("Releasing sema\n");
    sem_post(&sem1);

    sleep(5);
}

Solution

  • To create or simulate a situation where a thread overlays the work done by another thread, then remove the semaphore and strategically place the sleep, as:

    void * thread_func(void * arg)
    {
        //sem_wait(&sem1);
        //printf("Got sema\n");
        arr_th[idx]=itr;
        // print arr_th[idx]
        sleep(5);     <<== gives the threads more of a chance to wipe-out each other
        // print arr_th[idx]
        idx++; itr++;
        //printf("Releasing sema\n");
        //sem_post(&sem1);
    
        sleep(5);
    }
    

    You can add some printf statements that explicitly highlight the problem.

    volatile tells the compiler to not remove a variable that is not used or at least appears to be unused.

    You can update a linked list from multiple threads, but you must serialize the critical section of the code that updates the links (next and/or prev) in the list.

    In windows XP and above the CRT is thread safe, so each thread can issue malloc(), printf and the like without having to serialize the threads around those calls.