program is prone to deadlock when multi-variable used

  Give a brief introduction about the operation of your program and show that you understand the idea behind threads and mutual exclusion variable. Why do we need to use mutual exclusion to control the access of the three global variables? What is the potential problem if more than one task will require locking more than one mutual exclusion variable in its operation?

Answer:  Using parallel thread programming enhancing the computational power of the Processor by dividing program into independent threads. Thread is nothing but set of codes which the Operating system executes with the compiler. It is different from the traditional execution of the codes, where codes are executed sequentially and thus consuming more steps to finish a task. Parallel programming gives flexibility to coder to run simultaneous program using the multi-cores of a computer reducing the number of execution significantly, thus providing wide scope to handle large set of data and tasks simultaneously. Example when executing a large program in POSIX environment the memory allotted to the program is divided in cores, where first a thread executes and passing the value to the another thread function in the program. Parallel flow of such programs shortens the time of execution greatly. Since each thread has its own processing space therefore communication between threads will need to be done through a common global variable. Since multiple threads can access the same global variable this can leads to race condition. We know that each thread in the program has its own space, therefore to avoid confusion between programs we need to assign global variables in the beginning of the program. But now they are assessable to every thread in the program thus causing racing between threads. So it is obvious that we would like to avoid such scenario to occur, so in order to overcome such situation we use mutual exclusion variable, which is like a lock to prevent other thread's attempt to interfere with the Global variables currently  used by the executing thread and thus the thread have to wait till the operation of the concerned thread is over, failing to do so will result into deadlock condition where the program fails to execute further.  A mutex variable allow us to perform the lock/unlock action so that the critical section of the code can be protected. The main problem is circular wait, which is one of the four necessary condition required for deadlock. Therefore when multiple mutex are involved the order of the mutex lock and unlock is very important.

 

2.       Explain which part of the program is prone to deadlock when multi-variable is used and what measure you took to ensure that deadlock is avoided in the final program. Highlight the relevant section of your source code where multi-variable is used to control the access of the global variables.

Answer: the conditional portion of the thread function which manipulates the global variables for a particular thread, absence of proper locking sequence would result in a deadlock. To avoid deadlock in the final program we used mutex functions in the conditional loops in a ordered sequence unlocking them in the same order, thus avoiding deadlocks.

 

Following part of the program shows the application of multi-variable is used to control the access of the global variables(high lighted in yellow color).

 

void* PrintFactoryThread(void *threadid)
{

int i,process_id;
struct thread_data_struct *j_pt;
j_pt=(struct thread_data_struct *)threadid;
process_id=j_pt->thread_id; //assign thread id to process

printf("Factory thread starting.\n");
while (1)
{
pthread_mutex_lock(&revenue_lock);
pthread_mutex_lock(&product_lock);
pthread_mutex_lock(&parts_lock);
// lock revenue variable and test for termination conditon

if (revenue>=max_revenue)
{
pthread_mutex_unlock(&revenue_lock);
pthread_mutex_unlock(&product_lock);
pthread_mutex_unlock(&parts_lock);

break;
}
if ((product0))
{
product++;
parts--;
revenue--;
printf("Factory: manufacturing. | Parts=%d |Products=%d | Revenue=%d|\n",parts,product,revenue);
}



else
{
if (product>=max_products)
printf("Factory: stock overflow! | Parts=%d | Products=%d | Revenue=%d \n",parts,product,revenue);
else if (parts<1)
printf("Factory: no parts! | Parts=%d | Products=%d | Revenue=%d |\n",parts,product,revenue);
}

pthread_mutex_unlock(&revenue_lock);
pthread_mutex_unlock(&product_lock);
pthread_mutex_unlock(&parts_lock);

// delay the thread according to factory_delay
Sleep(factory_delay*1000);
}

 

3.Demonstrate that your program (include the program output as part of the final report) can produce the correct output with the following parameters. For each case comment if the output agree with the given parameters.

 

RTS_assignment C code


#include "stdafx.h"

#include "pthread.h"
#include
#include
#include

pthread_mutex_t product_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t parts_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t revenue_lock = PTHREAD_MUTEX_INITIALIZER;


int factory_delay=1;
int retail_delay=3;
int warehouse_delay=2;
int max_revenue=6;
int max_products=3;
int parts=0;
int revenue=0;
int product=0;


struct thread_data_struct{
int thread_id;
} ;


void* PrintFactoryThread(void *threadid)
{

int i,process_id;
struct thread_data_struct *j_pt;
j_pt=(struct thread_data_struct *)threadid;
process_id=j_pt->thread_id; //assign thread id to process


printf("Factory thread starting.\n");
while (1)
{
pthread_mutex_lock(&revenue_lock);
pthread_mutex_lock(&product_lock);
pthread_mutex_lock(&parts_lock);
// lock revenue variable and test for termination conditon

if (revenue>=max_revenue)
{
pthread_mutex_unlock(&revenue_lock);
pthread_mutex_unlock(&product_lock);
pthread_mutex_unlock(&parts_lock);

break;
}





if ((product0))
{
product++;
parts--;
revenue--;
printf("Factory: manufacturing. | Parts=%d |Products=%d | Revenue=%d|\n",parts,product,revenue);
}



else
{
if (product>=max_products)
printf("Factory: stock overflow! | Parts=%d | Products=%d | Revenue=%d |\n", parts, product,revenue);
else if (parts<1)
printf("Factory: no parts! | Parts=%d | Products=%d | Revenue=%d |\n", parts, product, revenue);
}

pthread_mutex_unlock(&revenue_lock);
pthread_mutex_unlock(&product_lock);
pthread_mutex_unlock(&parts_lock);

// delay the thread according to factory_delay
Sleep(factory_delay*1000);
}


printf("Factory thread terminating.\n");



//thread termination
pthread_exit(NULL);
return 0;
}

void* PrintRetailThread(void *threadid)
{

int i,process_id;
struct thread_data_struct *j_pt;
j_pt=(struct thread_data_struct *)threadid;
process_id=j_pt->thread_id; //assign thread id to process

printf("Thread Retail starting.\n");
while (1)
{
pthread_mutex_lock(&revenue_lock);
pthread_mutex_lock(&product_lock);
pthread_mutex_lock(&parts_lock);
// lock revenue variable and test for termination conditon
if (revenue>=max_revenue)
{
pthread_mutex_unlock(&revenue_lock);
pthread_mutex_unlock(&product_lock);
pthread_mutex_unlock(&parts_lock);

break;
}
if (product>0)
{
product--;
revenue+=3;
printf("Retail: sale! | Products=%d | Revenue=%d |\n", product, revenue);
}
else
{
printf("Retail: out of stock! | Products=%d | Revenue=%d |\n", product, revenue);
}

pthread_mutex_unlock(&revenue_lock);
pthread_mutex_unlock(&product_lock);
pthread_mutex_unlock(&parts_lock);

// delay the thread according to retail_delay
Sleep(retail_delay*1000);
}


printf("Retail thread terminating.\n");

pthread_exit(NULL);
return 0;
}

void* PrintWareHousethread(void *threadid)
{

int i,process_id;
struct thread_data_struct *j_pt;
j_pt=(struct thread_data_struct *)threadid;
process_id=j_pt->thread_id; //assign thread id to process


printf("Warehouse thread starting.\n");
while (1)
{
pthread_mutex_lock(&revenue_lock);
pthread_mutex_lock(&product_lock);
pthread_mutex_lock(&parts_lock);
// lock revenue variable and test for termination conditon
if (revenue>=max_revenue)
{

pthread_mutex_unlock(&revenue_lock);
pthread_mutex_unlock(&product_lock);
pthread_mutex_unlock(&parts_lock);
break;
}




if (parts<1)
{
parts+=2;
revenue--;
printf("Warehouse: supplying parts to warehouse.| Parts=%d | Revenue=%d\n", parts, revenue);
}

else
printf("Warehouse: no need to replenish parts | Parts=%d | Revenue=%d\n", parts, revenue);

pthread_mutex_unlock(&revenue_lock);
pthread_mutex_unlock(&product_lock);
pthread_mutex_unlock(&parts_lock);


Sleep(warehouse_delay*1000);

}


printf("Warehouse thread terminating.\n");



//thread termination
pthread_exit(NULL);
return 0;
}


int _tmain(int argc, _TCHAR* argv[])
{
pthread_t thread_Factory,thread_Retail,thread_WareHouse;

int rc;
// declear the array for the thread_data structure
struct thread_data_struct thread_data[3];

thread_data[0].thread_id=1; //assign thread id to thread structure


rc = pthread_create(&thread_Factory, NULL, PrintFactoryThread, (void *) &thread_data[0]);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
printf("Thread Factory: created.\n");



thread_data[1].thread_id=2; //assign thread id to thread structure


rc = pthread_create(&thread_Retail, NULL, PrintRetailThread, (void *) &thread_data[1]);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
printf("Thread Retail: created.\n");


thread_data[2].thread_id=3; //assign thread id to thread structure


rc = pthread_create(&thread_WareHouse, NULL, PrintWareHousethread, (void *) &thread_data[2]);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
printf("Thread WareHouse: created.\n");

pthread_join(thread_Factory, NULL);
pthread_join(thread_Retail, NULL);
pthread_join(thread_WareHouse, NULL);
printf("Joining all threads.\n");


return 0;
}

Case a.  factory_delay=1,  retail_delay=2,  warehouse_delay=3,  max_product=2 and

max_revenue=4.

Case b.  factory_delay=2,  retail_delay=1,  warehouse_delay=3,  max_product=3 and

max_revenue=4.

Case c.  factory_delay=1,  retail_delay=3,  warehouse_delay=2,  max_product=3 and

max_revenue=6.

   Related Questions in Programming Languages

©TutorsGlobe All rights reserved 2022-2023.