--%>

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

  • Q : Define Fetch-execute cycle

    Fetch-execute cycle: The simple set of steps which are endlessly recurring by a computer's Central Processing Unit for each and every program instruction: `Fetch the next instruction suggested by the program counter,' `update the program counter to pa

  • Q : Common Language Infrastructure or CLI

    What is the Common Language Infrastructure (CLI)? What relation does .NET have with the CLI?

  • Q : Explain Redundant value Redundant value

    Redundant value: The value of a data type which has no use or meaning in a particular context. For example, negative values would be redundant a class employing integer attributes to the model assignment marks. In several applications, redundant patte

  • Q : Why do I require TC Trustcenter

    Why do I require TC Trustcenter Publisher ID?

  • Q : What is a Pipe Pipe : It is a linkage

    Pipe: It is a linkage between the two program components. One component responds as a source of data, and writes into the pipe. The second components act as a receiver (that is, sink) for the data and reads from pipe.

  • Q : Define Java 2 SDK Java 2 SDK : It is a

    Java 2 SDK: It is a particular implementation of the abstract functionality explained in Sun's specification of Java 2 Platform.

  • Q : Meaning of active and passive objects

    Illustrate in brief the meaning of active and passive objects?

  • Q : Define the term Peripheral devices

    Define the term Peripheral devices: It is the devices attached to a computer, like disk drives, printers, mice, and so forth.

  • Q : Define Arithmetic operator Arithmetic

    Arithmetic operator: The Operators, like +, -, *, / and %, which generate a numerical outcome, as a part of an arithmetic expression.

  • Q : What is Low level programming languages

    Low level programming languages: It is frequently termed as `assembly languages’; these give little more than the fundamental instruction set of a particular Central Processing Unit. Therefore programs written in low level programming languages