程序代写代做代考 concurrency SOFT3410 Tutorial 6 Processes and Synchronisation 1

SOFT3410 Tutorial 6 Processes and Synchronisation 1
Question 1: Forking processes
UNIX systems use the fork() system call to allow existing processes to create new ones. The new process created by fork is called the child process, its creator is the parent process. fork is called once, but returns different values depending on which process you are in. The parent receives the process ID of the child, and the child receives zero. The return value of fork is the simplest way to distinguish between parent and child.
Both the child and parent process continue executing the instructions following the call to fork. The child is a copy of the parent, meaning the child gets a copy of the parent’s stack, heap, and data space. In this exercise, we will investigate how to use fork(). The headers in unistd.h and sys/*.h are included as part of the POSIX standard and rather than the C standard library.
#include
#include
#include
#include
int main(void) { int n = 4;
puts(“about to fork”); pid_t pid = fork();
if (pid < 0) { perror("unable to fork"); return 1; } if (pid == 0) { puts("child"); n++; // sleep(1); } else { puts("parent"); n *= 2; // wait(NULL); 1 } printf("fork returned %d, n is %d\n", pid, n); return 0; } • Compile and run the program a few times. Do the lines always get outputted in the same order? • Uncomment the sleep function so the child sleeps for a second, and try running the program. • Uncomment the wait function so the parent waits for the child to exit, and try running the program. • Rewrite your program to allow for communicate between processes to occur over a pipe. Question 2: Shared Memory and Locking Below is an example of two threads accessing shared data. Compile this program and observe the final value. struct thread_data { int value; }; void* work(void* arg) { struct thread_data* data = (struct thread_data*) arg; for(int i = 0; i < 1000000; i++) { data->value += 1; return NULL;
}
int main() {
}
}
struct thread_data data = { 0 };
pthread_t threads[2];
pthread_create(threads, NULL, work, &data); pthread_create(threads+1, NULL, work, &data);
for(int i = 0; i < 2; i++) { pthread_join(threads[i], NULL); } printf("%d\n", data.value); return 0; • When running this program multiple times, is the final result consistent? Concurrency Page 2 of 4 SOFT3410 Processes and Synchronisation 1 • If you have observed the final value does not meet the expected result, discuss why this could be happening • How could ensure that the final result is what we expect? What modifications do we need to make? Question 3: A bank with single customer Given the following program, what can you observe with this program? What is the expected value of account? Does it meet the expected the value or does something occur? • Do any value not get updated? • What should be the final value? #include #include #include #define THREAD_COUNT (2) struct thread_data {
int* account; int amount;
};
void* operation_on_money(void* data) { struct thread_data* tdata = data; int amount = tdata->amount; for(int i = 0; i < 60; i++) { } *(tdata->account) += amount;
sleep(1);
}
return NULL;
int main() {
int data = 100;
pthread_t threads[THREAD_COUNT];
struct thread_data tdata[THREAD_COUNT] = {
{ .account = &data, .amount = 10 },
{ .account = &data, .amount = -10 }
};
for(int i = 0; i < THREAD_COUNT; i++) { pthread_create(threads+i, NULL, operation_on_money, tdata+i); } for(int i = 0; i < THREAD_COUNT; i++) { SOFT3410 Processes and Synchronisation 1 Concurrency Page 3 of 4 } pthread_join(threads[i], NULL); return 0; } Question 4: Locking the bank Using what you have learned from the previous questions, use mutexes to prevent the above race con- dition from occurring on the accounts. Given the following function signature deposit(struct account* from, struct account* to, int amount),considerhowyoucouldencounter a deadlock. Elabroate and explain why you would encounter the deadlock and how you could prevent it from occurring. Question 5: Coarse Grained Locking Use your linked list that you have constructed previously or you could construct a dynamic array for this task if you had not completed the linked list. The following functions must be thread safe. void linkedlist_map_put(struct linkedlist_map* map, void* key void* value); void* linkedlist_map_get(struct linkedlist_map* map, void* key); void* linkedlist_map_remove(struct linkedlist_map* map, void* key); Question 6: Fine-grained Locking Instead of locking the linked list with a simple lock, lock each node instead. Divise a test case where you believe the fine-grained linked list would perform better than the coarse grained linked list. SOFT3410 Processes and Synchronisation 1 Concurrency Page 4 of 4