Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

In this assignment, implement two threads and thread synchronization statements

ID: 3579869 • Letter: I

Question

In this assignment, implement two threads and thread synchronization statements for updating a shared variable called “counter”. Look at the code in file threadsync.c carefully. It contains the necessary instructions as to where you need to put what code.

code must take from the user the initial value of the counter from argv[1], value of variable incr from argv[2] and value of decr from argv[3]. If the number of arguments are less than 3, then your code MUST print an error message with “Usage: threadsync ” and abort, without creating the two threads. Example: “./threadsync 1000 10 5” initializes counter with 1000, incr with 10 and decr with 5.

DO NOT use argv[] to get the values of counter, incr and decr from the user. Instead, you should use getopt() to get the values in the following manner: 1. –c option to get the initial value of counter 2. –i option to get the value of incr 3. –d option to get the value of decr If the user uses an option other than “-c”, -“i” and “-d”, it must print an error message with “Usage: threadsync –c -d and abort, without creating the two threads. Example: “./threadsync –c 1000 –i 10 –d 5” initializes counter with 1000, incr with 10 and decr with 5.

/*
* For testing if you run ./threadsync -c 0 -i 1 -d 1 (or for 306 students if you take counter as 0, incr as 1 and decr as 1 from argc, argv),
* then final output should be printed out as 0. That is when your code is right.
*/


#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>

#define loops 1000000

/* This is your global variable that will be updated by multiple threads - need to synchronize access to it */
int counter;

/* Your code goes here: initialize a mutex_lock. Remember, since the mutex lock is shared between threads,
it MUST BE DECLARED AS A GLOBAL variable */


void* increment(void *arg)
{
   /* Your code goes here: copy the value of arg to the local int variable incr_step */
   int incr_step;

   unsigned long int i;
   /* Your code goes here: you need to add thread synchronization statements (lock and unlock)
for accessing the shared variable "counter" inside the loop.

Points will be deducted, if your synchronization block covers more
statements than absolutely necessary! Remember: since locking reduces
concurrency, you MUST MAKE SURE that you lock only the minimum set of statements and for MINIMUM amount of time!
*/  
   for(i=0; i<loops;i++) {
       counter = counter + incr_step;
      
       // I have commented this line out. You can uncomment it for debugging.
       //printf("Thread ID %lu --> counter = %d", pthread_self(), counter);
   }

   return NULL;   /* We MUST return NULL since thread function signature requires returning (void *) datatype */
}

void* decrement(void *arg)
{
   /* Your code goes here: copy the value of arg to the local int variable decr_step */
   int decr_step;

   unsigned long int i;
   /* Your code goes here: you need to add thread synchronization statements (lock and unlock)
for accessing the shared variable "counter" inside the loop.

Points will be deducted, if your synchronization block covers more
statements than absolutely necessary! Remember: since locking reduces
concurrency, you MUST MAKE SURE that you lock only the minimum set of statements and for MINIMUM amount of time!
*/  
   for(i=0; i<loops;i++) {
       counter = counter - decr_step;
      
       // I have commented this line out. You can uncomment it for debugging.
       //printf("Thread ID %lu --> counter = %d", pthread_self(), counter);
   }

   return NULL;   /* We MUST return NULL since thread function signature requires returning (void *) datatype */
}

int main(int argc, char *argv[])
{
   int i = 0;
   int err;
   pthread_t tid[2];        /* We will store the thread IDs in an array */
  
   int incr, decr;  
   /* For CS306, your code goes here: copy argv[1] to counter, argv[2] to incr and argv[3] to decr.
These will be the arguments that you respectively pass to the two threads you will
create next: increment() and decrement().

   For CS491 ONLY: instead of using argv[1], argv[2] and argv[3], you MUST use getopt() as mentioned in the instructions
    to get the values of counter, incr and decr respectively.
   */


   /* Your code goes here: create the thread with entry point increment() in tid[0]. your code
MUST check for thread creation errors and print the apprpriate error message before aborting */
  
  
   /* Your code goes here: create the thread with entry point decrement() in tid[1]. your code
MUST check for thread creation errors and print the apprpriate error message before aborting */

  
   /* Your code goes here: Now write the necessary code for joiing back the two threads */
  

   /* Your code goes here: finally, destroy the mutex you created - always remember to destroy all mutexes before exiting code! */
  
  
   // Finally let's check what the value of counter is after all that processing by the above two threads
   // For testing if you run ./threadsync -c 0 -i 1 -d 1 (or for 306 students if you take counter as 0, incr as 1 and decr as 1 from argc, argv),
   // then this line should print out 0 as the answer. That is when your code is right.
   printf("counter = %d ", counter);
  
   return 0;
}

Explanation / Answer

#include <stdio.h>
#include <stdio.h>
#include <stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>

#define loops 1000000
//#define loops 306
/* This is your global variable that will be updated by multiple threads - need to synchronize access to it */
int counter;
/* Your code goes here: initialize a mutex_lock. Remember, since the mutex lock is shared between threads,
it MUST BE DECLARED AS A GLOBAL variable */

pthread_mutex_t count_mutex;
long long count;
int counter;
void* increment(void *arg)
{
   /* Your code goes here: copy the value of arg to the local int variable incr_step */
   int incr_step;
   unsigned long int i;
   /* Your code goes here: you need to add thread synchronization statements (lock and unlock)
   for accessing the shared variable "counter" inside the loop.
   Points will be deducted, if your synchronization block covers more
   statements than absolutely necessary! Remember: since locking reduces
   concurrency, you MUST MAKE SURE that you lock only the minimum set of statements and for MINIMUM amount of time!
   */
   incr_step = *(int*)arg;
   printf("%d ",incr_step);
   for (i = 0; i<loops; i++) {
  
   pthread_mutex_lock(&count_mutex);
   counter = counter + incr_step;
   printf("Counter value in increament: %d ",counter);
      pthread_mutex_unlock(&count_mutex);

       // I have commented this line out. You can uncomment it for debugging.
       //printf("Thread ID %lu --> counter = %d", pthread_self(), counter);
   }
   return NULL; /* We MUST return NULL since thread function signature requires returning (void *) datatype */
}
void* decrement(void *arg)
{
   /* Your code goes here: copy the value of arg to the local int variable decr_step */
   int decr_step;
   unsigned long int i;
   /* Your code goes here: you need to add thread synchronization statements (lock and unlock)
   for accessing the shared variable "counter" inside the loop.
   Points will be deducted, if your synchronization block covers more
   statements than absolutely necessary! Remember: since locking reduces
   concurrency, you MUST MAKE SURE that you lock only the minimum set of statements and for MINIMUM amount of time!
   */
   decr_step = *(int*)arg;
   printf("%d ",decr_step);
   for (i = 0; i<loops; i++) {
      
pthread_mutex_lock(&count_mutex);
   counter = counter - decr_step;
   printf("Counter value in decreament : %d ",counter);
   pthread_mutex_unlock(&count_mutex);
       // I have commented this line out. You can uncomment it for debugging.
       //printf("Thread ID %lu --> counter = %d", pthread_self(), counter);
   }
   return NULL; /* We MUST return NULL since thread function signature requires returning (void *) datatype */
}
int main(int argc, char *argv[])
{
   int i = 0;
   int err;
   pthread_t tid[2]; /* We will store the thread IDs in an array */

   int incr, decr;
   /* For CS306, your code goes here: copy argv[1] to counter, argv[2] to incr and argv[3] to decr.
   These will be the arguments that you respectively pass to the two threads you will
   create next: increment() and decrement().
   For CS491 ONLY: instead of using argv[1], argv[2] and argv[3], you MUST use getopt() as mentioned in the instructions
   to get the values of counter, incr and decr respectively.
   */
   char c;
   int inc,d;
   if( argc < 3)
   {
   printf("Usage : “./threadsync 1000 10 5 ");
   exit(-1);
   }
     
while((c = getopt(argc, argv, "c:i:d:")) != EOF)
{
switch (c)
{
case 'c':
//cout << optarg << endl;
counter = atoi(optarg) ;
printf("counter = %d ",counter);
break;
case 'i':
//cout << optarg << endl;
inc = atoi(optarg) ;
printf("i = %d ",inc);
break;
case 'd':
//cerr << "Missing option." << endl;
d =atoi(optarg) ;
printf("d = %d ",d);
break;
default:
printf("no valid option ");
break;
}
}

   /* Your code goes here: create the thread with entry point increment() in tid[0]. your code
   MUST check for thread creation errors and print the apprpriate error message before aborting */


   /* Your code goes here: create the thread with entry point decrement() in tid[1]. your code
   MUST check for thread creation errors and print the apprpriate error message before aborting */
   /*printf("tid%d: %d ",tid[0]);
   printf("tid%d: %d ",tid[1]);
   printf("counter = %d i = %d d = %d ",counter,inc,d);*/
   err = pthread_create(&(tid[0]), NULL, &increment, (void*)&inc);
if (err != 0)
printf(" can't create thread :[%s]", strerror(err));
else
printf(" Thread created successfully ");
err = pthread_create(&(tid[1]), NULL, &decrement,(void*)&d);
if (err != 0)
printf(" can't create thread :[%s]", strerror(err));
else
printf(" Thread created successfully ");
  
  
   /* Your code goes here: Now write the necessary code for joiing back the two threads */
pthread_join(tid[0],NULL);
  
pthread_join(tid[1],NULL);
   /* Your code goes here: finally, destroy the mutex you created - always remember to destroy all mutexes before exiting code! */


   // Finally let's check what the value of counter is after all that processing by the above two threads
   // For testing if you run ./threadsync -c 0 -i 1 -d 1 (or for 306 students if you take counter as 0, incr as 1 and decr as 1 from argc, argv),
   // then this line should print out 0 as the answer. That is when your code is right.
   printf("counter in main = %d ", counter);

   return 0;
}

------------------------------------------------------------------------

output for : ./threadsync -c 0 -i 1 -d 1

Counter value in increament: -13                                                                                                                                                

Counter value in increament: -12                                                                                                                                                

Counter value in increament: -11                                                                                                                                                

Counter value in increament: -10                                                                                                                                                

Counter value in increament: -9                                                                                                                                                 

Counter value in increament: -8                                                                                                                                                 

Counter value in increament: -7                                                                                                                                                 

Counter value in increament: -6                                                                                                                                                 

Counter value in increament: -5                                                                                                                                                 

Counter value in increament: -4                                                                                                                                                 

Counter value in increament: -3                                                                                                                                                 

Counter value in increament: -2                                                                                                                                                 

Counter value in increament: -1                                                                                                                                                 

Counter value in increament: 0                                                                                                                                                  

counter in main = 0                                                                                                                                                             

-----------------------------------------------

output for : ./threadsync -c 1000 -i 10 -d 5

Counter value in decreament : 5001050                                                                                                                                           

Counter value in decreament : 5001045                                                                                                                                           

Counter value in decreament : 5001040                                                                                                                                           

Counter value in decreament : 5001035                                                                                                                                           

Counter value in decreament : 5001030                                                                                                                                           

Counter value in decreament : 5001025                                                                                                                                           

Counter value in decreament : 5001020                                                                                                                                           

Counter value in decreament : 5001015                                                                                                                                           

Counter value in decreament : 5001010                                                                                                                                           

Counter value in decreament : 5001005                                                                                                                                           

Counter value in decreament : 5001000

counter in main = 5001000