Starting from:
$35

$29

CISC2005 Exercise 04

  1. Prerequisites
  1. Successful installation of *nix terminal (e.g., WSL, cygwin) or a *nix operating system (e.g., Linux, Mac).

For Windows system, I recommend you to install WSL. https://learn.microsoft.com/en-us/windows/wsl/install

  1. Successful installation of a C compiler, GCC is recommended.
  2. Successful installation of a text editor, VIM or Emacs is recommended.
  1. Answering Questions raised in last week
  1. In last week, someone noticed that some codes may sometimes behave strangely, i.e., some output repeated twice and the printf function seems like being executed repeatedly (typically in eclipse + cygwin environment). The reason is the buffering mechanism of stdout . Specifically, once you observe a repeated printing, you could add a sleep(5) command before fork() , and then you can see that before sleeping the desired output is not yet printed. After the fork() is called, two processes are simultaneously running so the buffered outputs are printed twice. To mitigate this behaviour, you could palce a fflush(stdout) command before calling the fork() function, enforcing flush of stdout in advance.
  1. Compile Instruction for thread-based program

In case of using Linux system, you need to link with pthread library using -l pthread during compile phase. Otherwise, you will fail to compile the source code. As an example, you should change your compile command from gcc q1.c -o q1 to gcc q1.c -l pthread -o q1.

Eclipse or other IDE would automatically assemble this library during compiling phase so you don’t have to explicitly do so.

  1. Tasks

In this section, students are required to execute the following codes, and try to understand the behaviour. For each program, students should capture a screenshot of the successful execution, and answer attached questions briefly. In the submission file, please attach the execution screenshot and the explanation of each question in sequence.

Q1: Execute the following code, and state why two PIDs are the same and why two threadIDs are different.

#include <stdio.h>

#include <unistd.h>

#include <pthread.h>

void kidfunc() {

printf("Kid PID is %d, thread ID is %d\n", getpid(), pthread_self());

}

int main() {

pthread_t kid;

pthread_create(&kid, NULL, kidfunc, NULL);

printf("Parent PID is %d, thread ID is %d\n", getpid(), pthread_self());

pthread_join(kid, NULL);

printf("Complete!\n");

return 0;

}



Q2: Execute the following code, and state if the global data in the last output is deterministic or not and why.

#include <stdio.h>

#include <unistd.h>

#include <pthread.h>

int glob_data = 5;

void* kidfunc() {

glob_data = 15;

}

int main() {

pthread_t kid;

printf("Start of program. Global data = %d.\n", glob_data);

pthread_create(&kid, NULL, kidfunc, NULL);

glob_data = 10;

pthread_join(kid, NULL);

printf("End of program. Global data = %d.\n", glob_data);

return 0;

}



Q3: Execute the following code, and state 1) why the variable this_is_global equals to 1002 in thread test, 2) Identify whether the address of variables in two threads are identical in thread test and why 3) why the modification occurred in child process doesn’t influence the value in parent process, 4) why the address of variables in two processes are identical in process test.

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

#include <unistd.h>

int this_is_global;

void thread_func(void *dummy) {

int local_thread;

printf("Thread %d, pid %d, addresses: &this_is_global: %X, &local: %X\n",

pthread_self(), getpid(), &this_is_global, &local_thread);

this_is_global++;

printf("In Thread %d, incremented this_is_global=%d\n", pthread_self(),

this_is_global);

pthread_exit(0);

}

int main() {

// thread test

pthread_t thread1, thread2;

printf("First, we create two threads to see better what context they share...\n");

this_is_global = 1000;

printf("Set this_is_global=%d\n", this_is_global);

pthread_create(&thread1, NULL, (void*) &thread_func, (void*) NULL);

pthread_create(&thread2, NULL, (void*) &thread_func, (void*) NULL);

pthread_join(thread1, NULL);

pthread_join(thread2, NULL);

printf("After threads, this_is_global=%d\n", this_is_global);

printf("\n");

printf("After testing threads, let's call fork..\n");

// process test

int local_main = 17;

this_is_global = 17;

printf("Before fork(), local_main=%d, this_is_global=%d\n", local_main, this_is_global);

fflush(stdout);

int pid = fork();

if (pid == 0) {

printf("In child, pid %d: &this_is_global: %X, &local_main: %X\n", getpid(), &this_is_global, &local_main);

local_main = 13;

this_is_global = 23;

printf("In child, local main=%d, this_is_global=%d\n", local_main, this_is_global);

exit(0);

} else {

printf("In parent, pid %d: &this_is_global: %X, &local_main: %X\n", getpid(), &this_is_global, &local_main);

wait(NULL);

printf("In parent, local_main=%d, this_is_global=%d\n", local_main, this_is_global);

exit(0);

}

}



Q4: Execute the following code multiple times and state why the result is not deterministic.

#include <stdio.h>

#include <pthread.h>

#include <stdlib.h>

#include <unistd.h>

int tot_items = 0;

struct kidrec {

int data;

pthread_t id;

};

#define NKIDS 10

void* kidfunc(void *p) {

int *ip = (int*) p;

int tmp, n;

tmp = tot_items;

for (n = 500000; n--;)

tot_items = tmp + *ip;

}

int main() {

struct kidrec kids[NKIDS];

for (int m = 0; m < NKIDS; ++m) {

kids[m].data = m + 1;

pthread_create(&kids[m].id, NULL, kidfunc, &kids[m].data);

}

for (int m = 0; m < NKIDS; ++m)

pthread_join(kids[m].id, NULL);

printf("End of Program. Grand Total = %d\n", tot_items);

return 0;

}



More products