Question

In: Computer Science

C Language - The function 'make_enzyme_threads' has a memory bug. Fix this by simply re-ordering the...

C Language - The function 'make_enzyme_threads' has a memory bug. Fix this by simply re-ordering the lines in this function. It is simple fix but may take a while for you to find it. As a hint, you may want to pay attention to the addresses of the pointers that are passed to the individual enzymes.

//enzyme.h contents

//Note I could not use tag openers in the includes.

#define _GNU_SOURCE
#include (pthread.h)
#include (stdio.h)
#include (sys/types.h)
#include (string.h)
#include (stdlib.h)
#include (unistd.h)

#define MAX 100

typedef struct {
char *string; // keep testing and swap contents if necessary so that string[0] < string[1]
int swapcount; // used later
} thread_info_t;

extern int please_quit;
extern int workperformed;

void *run_enzyme(void *data);
int make_enzyme_threads(pthread_t * enzymes_tid, char *string, void *(*fp)(void *));
int join_on_enzymes(pthread_t *threads_tid, int n);

int smp2_main(int, char**);

// XXX macOS compatibility
#ifdef __APPLE__
#define pthread_yield() sched_yield()
#endif

//enzyme.c contents

#include "enzyme.h"

int please_quit;
int use_yield;
int workperformed;

// The code executed by each enzyme.
void *run_enzyme(void *data) {
//This function should :
//1. Cast the void* pointer to thread_info_t* (defined in enzyme.h)
//2. Initialize the swapcount to zero
  //3. Set the cancel type to PTHREAD_CANCEL_ASYNCHRONOUS (see pthread_setcanceltype)
/*4. If the first letter of the string is a C then call pthread_cancel on this thread.
(see also, pthread_self)
Note, depeneding on your platform (and specifically for macOS) you have
to replace the call to pthread_cancel with
pthread_exit(PTHREAD_CANCELED) in order to make the cancel test
pass.*/
//5. Create a while loop that only exits when please_quit is nonzero
/*6. Within this loop: if the first character of the string has an ascii
value greater than the second (info->string[0] > info->string[1]) then
- Set workperformed = 1
- Increment swapcount for this thread
- Swap the two characters around*/
//7. If "use_yield" is nonzero then call pthread_yield at the end of the loop.
//8. Return a pointer to the updated structure.

while(0) {
pthread_yield();
};
return NULL;
}


// Make threads to sort string.
// Returns the number of threads created.
// There is a memory bug in this function.
int make_enzyme_threads(pthread_t * enzymes, char *string, void *(*fp)(void *)) {
int i, rv, len;
thread_info_t *info;
len = strlen(string);
info = (thread_info_t *)malloc(sizeof(thread_info_t));

for (i = 0; i < len - 1; i++) {
info->string = string + i;
rv = pthread_create(enzymes + i, NULL, fp, info);
if (rv) {
fprintf(stderr,"Could not create thread %d : %s\n", i, strerror(rv));
exit(1);
}
}
return len - 1;
}


// Join all threads at the end.
// Returns the total number of swaps.
int join_on_enzymes(pthread_t *threads, int n) {
int i;
int totalswapcount = 0;

// Just to make the code compile. You will need to replace every usage of
// this variable in the code below. When you are done, placeholder can be
// deleted.

int holder = 0;

for(i = 0; i < n; i++) {
void *status;
int rv = pthread_join(threads[i], &status);

if (holder) {
fprintf(stderr,"Can't join thread %d:%s.\n",i,strerror(rv));
continue;
}

if ((void*)holder == PTHREAD_CANCELED) {
continue;
} else if (status == NULL) {
printf("Thread %d did not return anything\n",i);
} else {
printf("Thread %d exited normally: ",i);// Don't change this line
int threadswapcount = holder;
// Hint - you will need to cast something.
printf("%d swaps.\n",threadswapcount); // Don't change this line
totalswapcount += threadswapcount;// Don't change this line
}
}
return totalswapcount;
}

/* Wait until the string is in order. Note, we need the workperformed flag just
* in case a thread is in the middle of swapping characters so that the string
* temporarily is in order because the swap is not complete.
*/
void wait_till_done(char *string, int n) {
int i;
while (1) {
pthread_yield();
workperformed = 0;
for (i = 0; i < n; i++)
if (string[i] > string[i + 1]) {
workperformed = 1;
}
if (workperformed == 0) {
break;
}
}
}

void * sleeper_func(void *p) {
sleep( (int) p);
// Actually this may return before p seconds because of signals.
// See man sleep for more information
printf("sleeper func woke up - exiting the program\n");
exit(1);
}

int smp2_main(int argc, char **argv) {
pthread_t enzymes[MAX];
int n, totalswap;
char string[MAX];

if (argc <= 1) {
fprintf(stderr,"Usage: %s \n",argv[0]);
exit(1);
}

// Why is this necessary? Why cant we give argv[1] directly to the thread
// functions?
strncpy(string,argv[1],MAX);

please_quit = 0;
use_yield = 1;

printf("Creating threads...\n");
n = make_enzyme_threads(enzymes, string, run_enzyme);
printf("Done creating %d threads.\n",n);

pthread_t sleeperid;
pthread_create(&sleeperid, NULL, sleeper_func, (void*)5);

wait_till_done(string, n);
please_quit = 1;
printf("Joining threads...\n");
totalswap = join_on_enzymes(enzymes, n);
printf("Total: %d swaps\n", totalswap);
printf("Sorted string: %s\n", string);

exit(0);
}

Solutions

Expert Solution

Working code implemented in C and appropriate comments provided for better understanding.

Here I am attaching code for these files:

  • enzyme.c
  • enzyme.h

enzyme.c:

#include "enzyme.h"

int please_quit;
int use_yield;
int workperformed;

// error handler
void handle_error(int error_no, const char * const msg) {
fprintf(stderr, msg, error_no);
exit(EXIT_FAILURE);
}

// The code each enzyme executes.
void* run_enzyme(void *data) {
// This function should :
// 1. cast the void* pointer to thread_info_t*
thread_info_t *thread_data = (thread_info_t *)data;
// 2. initialize the swapcount to zero
thread_data->swapcount = 0;
int result;
// 3. Set the cancel type to PTHREAD_CANCEL_ASYNCHRONOUS
result = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
if (result) {
handle_error(result, "error code %d: pthread_setcanceltype\n");
}
// 4. If the first letter of the string is a C then call pthread_cancel on this thread.
if (thread_data->string[0] == 'C') {
result = pthread_cancel(pthread_self());
if (result) {
handle_error(result, "error code %d: pthread_cancel\n");
}
}
// 5. Create a while loop that only exits when please_quit is nonzero
while (please_quit == 0) {
// 6. Within this loop: if the first character of the string has an ascii value greater than the second (s[0] > s[1]) then -
// Set workperformed=1, increment swapcount for this thread, then swap the two characters around
if (thread_data->string[0] > thread_data->string[1]) {
// printf("thead %d before swap: %c, %c\n", pthread_self(), thread_data->string[0], thread_data->string[1]);
workperformed = 1;
thread_data->swapcount++;
// swap characters
thread_data->string[0] ^= thread_data->string[1];
thread_data->string[1] ^= thread_data->string[0];
thread_data->string[0] ^= thread_data->string[1];
// printf("thead %d after swap: %c, %c\n", pthread_self(), thread_data->string[0], thread_data->string[1]);
// If "use_yield" is nonzero then call pthread_yield at the end of the loop.
if (use_yield) {
result = pthread_yield();
if (result) {
handle_error(result, "error code %d: pthread_yield\n");
}
}
}
}
  
// 7. Return a pointer to the updated structure.
return thread_data;
}

// Make threads to sort string.
// Returns the number of threads created.
// There is a memory bug in this function.
int make_enzyme_threads(pthread_t *enzymes, char *string, void *(*fp)(void *)) {
int i, rv, len;
thread_info_t *info;
len = strlen(string);

for (i = 0; i < len - 1; i++) {
info = (thread_info_t *)malloc(sizeof(thread_info_t));
info->string = string + i;
rv = pthread_create(enzymes + i, NULL, fp, info);
if (rv) {
fprintf(stderr, "Could not create thread %d : %s\n",
i, strerror(rv));
exit(1);
}
}
  
return len - 1;
}

// Join all threads at the end.
// Returns the total number of swaps.
int join_on_enzymes(pthread_t *threads, int n) {
int i;
int totalswapcount = 0;
int whatgoeshere = 0; // just to make the code compile
// you will need to edit the code below
for (i = 0; i < n; i++) {
void *status;
int rv = pthread_join(threads[i], &status);

if (rv) {
fprintf(stderr,"Can't join thread %d:%s.\n",i,strerror(rv));
continue;
}

if ((void*)status == PTHREAD_CANCELED) {
continue;
} else if (status == NULL) {
printf("Thread %d did not return anything\n", i);
} else {
printf("Thread %d exited normally: ", i);// Don't change this line
int threadswapcount = ((thread_info_t *)status)->swapcount;
// Hint - you will need to cast something.
printf("%d swaps.\n",threadswapcount); // Don't change this line
totalswapcount += threadswapcount;// Don't change this line
}
}
  
return totalswapcount;
}

/* Wait until the string is in order. Note, we need the workperformed flag just in case a thread is in the middle of swapping characters
so that the string temporarily is in order because the swap is not complete.
*/
void wait_till_done(char *string, int n) {
int i;
while (1) {
sched_yield();
workperformed = 0;
for (i = 0; i < n; i++) {
if (string[i] > string[i + 1]) {
workperformed = 1;
}
}
if (workperformed == 0) break;
}
}

void * sleeper_func(void *p) {
sleep( (int) p);
// Actually this may return before p seconds because of signals.
// See man sleep for more information
printf("sleeper func woke up - exiting the program\n");
exit(1);
}

int smp2_main(int argc, char **argv) {
pthread_t enzymes[MAX];
int n, totalswap;
char string[MAX];

if (argc <= 1) {
fprintf(stderr,"Usage: %s <word>\n",argv[0]);
exit(1);
}
  
strncpy(string, argv[1], MAX); // Why is this necessary? Why cant we give argv[1] directly to the thread functions?

please_quit = 0;
use_yield = 1;
  
printf("Creating threads...\n");
n = make_enzyme_threads(enzymes, string, run_enzyme);
printf("Done creating %d threads.\n",n);
  
pthread_t sleeperid;
pthread_create(&sleeperid, NULL, sleeper_func, (void*)5);

wait_till_done(string, n);
please_quit = 1;
printf("Joining threads...\n");
totalswap = join_on_enzymes(enzymes, n);
printf("Total: %d swaps\n", totalswap);
printf("Sorted string: %s\n", string);
  
exit(0);
}

enzyme.h:

#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#define MAX 100

typedef struct {
char *string; // keep testing and swap contents if necessary so that string[0] < string[1]
int swapcount; // used later
} thread_info_t;

extern int please_quit;

extern int workperformed;

void *run_enzyme(void *data);

int make_enzyme_threads(pthread_t * enzymes_tid, char *string, void *(*fp)(void *));

int join_on_enzymes(pthread_t *threads_tid, int n);

int smp2_main(int, char**);


Related Solutions

The function 'make_enzyme_threads' has a memory bug. Fix this by simply re-ordering the lines in this...
The function 'make_enzyme_threads' has a memory bug. Fix this by simply re-ordering the lines in this function. It is simple fix but may take a while for you to find it. As a hint, you may want to pay attention to the addresses of the pointers that are passed to the individual enzymes #include "enzyme.h" int please_quit; int use_yield; int workperformed; // The code executed by each enzyme. void *run_enzyme(void *data) { /* This function should : 1. Cast the...
In C++, Implement the heapafication operation. Do not re-implement the binary tree class. Simply create a...
In C++, Implement the heapafication operation. Do not re-implement the binary tree class. Simply create a funcntion that takes in a binary tree and heapafies it. Meaning it takes in a pointer to a binary tree and converts it into a heap. (You may choose max or min heap).
how to accept string from shared memory using c language ?
how to accept string from shared memory using c language ?
use the python language and fix the error code #Write a function called rabbit_hole. rabbit_hole should...
use the python language and fix the error code #Write a function called rabbit_hole. rabbit_hole should have #two parameters: a dictionary and a string. The string may be #a key to the dictionary. The value associated with that key, #in turn, may be another key to the dictionary. # #Keep looking up the keys until you reach a key that has no #associated value. Then, return that key. # #For example, imagine if you had the following dictionary. #This one...
Code in C++ programming language description about read and write data to memory example.
Code in C++ programming language description about read and write data to memory example.
Programming in C language (not C++) Write a runction derinition for a function called SmallNumbers that...
Programming in C language (not C++) Write a runction derinition for a function called SmallNumbers that will use a while loop. The function will prompt the user to enter integers ine by one, until the user enters a negative value to stop. The function will display any integer that is less than 25. Declare and initialize any variables needed. The function takes no arguments and has a void return type.
How to convert Sudo Code to C language? keyboard_process() {//insert a string. //check for shared memory...
How to convert Sudo Code to C language? keyboard_process() {//insert a string. //check for shared memory If(shared memory not full) { //sendthe string to the shared memory //send signal to process; }
C++ code won't run. Fix? //========================================================== #include <conio.h> // For function getch() #include <cstdlib> // For...
C++ code won't run. Fix? //========================================================== #include <conio.h> // For function getch() #include <cstdlib> // For several general-purpose functions #include <fstream> // For file handling #include <iomanip> // For formatted output #include <iostream> // For cin, cout, and system #include <string> // For string data type using namespace std; // So "std::cout" may be abbreviated to "cout" //Converting hexadecimal to binary int main() {    char binarynum[65], hexa[17];    //Using long int because it has greater capacity    long int...
C Language - Programming Write a function that takes an array of ints, and the size...
C Language - Programming Write a function that takes an array of ints, and the size of the array – another int. It also returns a double. Call this one ‘average.’ Return a double that is the average of the values in the array. Demonstrate that it works by finding the average of an array with these values {78, 90, 56, 99, 88, 68, 92} Write a function that takes one double parameter, and returns a char. The parameter represents...
In c++ language, write a void function GetYear that prompts for and inputs the year the...
In c++ language, write a void function GetYear that prompts for and inputs the year the operator was born (type int) from standard input. The function returns the user’s birth year through the parameter list (use pass by reference) unless the user enters an invalid year, in which case a BadYear exception is thrown. To test for a bad year, think about the range of acceptable years. It must be 4 digits (i.e. 1982) and it cannot be greater than...
ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT