diff --git a/Lab4/.idea/.gitignore b/Lab4/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/Lab4/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/Lab4/.idea/Lab4.iml b/Lab4/.idea/Lab4.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/Lab4/.idea/Lab4.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Lab4/.idea/codeStyles/codeStyleConfig.xml b/Lab4/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/Lab4/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/Lab4/.idea/misc.xml b/Lab4/.idea/misc.xml new file mode 100644 index 0000000..79b3c94 --- /dev/null +++ b/Lab4/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Lab4/.idea/modules.xml b/Lab4/.idea/modules.xml new file mode 100644 index 0000000..0c0d001 --- /dev/null +++ b/Lab4/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Lab4/.idea/vcs.xml b/Lab4/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/Lab4/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Lab4/CMakeLists.txt b/Lab4/CMakeLists.txt new file mode 100644 index 0000000..030d41a --- /dev/null +++ b/Lab4/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.22) +project(Lab4 C) + +set(CMAKE_C_STANDARD 99) + +add_executable(Lab4 Lab4.c) diff --git a/Lab4/Lab4.c b/Lab4/Lab4.c new file mode 100644 index 0000000..76328f4 --- /dev/null +++ b/Lab4/Lab4.c @@ -0,0 +1,100 @@ +/* + * Question 2: You see the number 1 most of the time. It is sometimes different because there are periods of time when the threads are reading/writing to the same place, but with the number of increments being 100, it is not likely that the threads will be reading/writing at the same time. In the CPU what happens is that a value is loaded into a register, while another thread completes a task, and then the value is written back to the memory. This leads to missing increments/decrements. + * + * Question 4: You see the number 1 often. Since the number of increments is 1000, the chance has increased for threads to be reading/writing at the same time. This leads to more missing increments/decrements. + * + * Question 6: You see the number 1 almost never. The number of loops at this point almost guarantees that the threads will be reading/writing at the same time, and the counter missing increments/decrements. + * + * Question 8: The number 1 is the only thing displayed. This is because the mutex lock ensures that the threads will not be reading/writing at the same time, and the counter will not miss increments/decrements. When another thread tried to lock the mutex, it waits for it to first become unlocked, ensuring proper thread synchronization. + */ + + +#include +#include +#include +#include +#include + +#define RANDOM_WITHIN_RANGE(a, b, seed) (rand_r(&seed)%b+a) + +int gv = 1; +pthread_mutex_t mutex; +sem_t sem; + +#define loop 10000 + +void *inc() { + for (int i = 0; i < loop; i++) { + pthread_mutex_lock(&mutex); + gv++; + pthread_mutex_unlock(&mutex); + } +} + +void *dec() { + for (int i = 0; i < loop; i++) { + pthread_mutex_lock(&mutex); + gv--; + pthread_mutex_unlock(&mutex); + } +} + +void *minus() { + int i = 0; + for (i = 0; i < 10; i++) { + printf("-"); + sem_wait(&sem); + } + return NULL; +} + +void *plus(void *argg) { + unsigned int seed = *((unsigned int *) argg); + int interval = RANDOM_WITHIN_RANGE(100000, 500000, seed); + int i = 0; + + for (i = 0; i < 10; i++) { + printf("+"); + //usleep(interval); + sem_post(&sem); + } + return NULL; +} + +int main(int argc, char **argv) { + setvbuf(stdout, NULL, _IONBF, 0); + int i = 0; + + // Init Mutex + pthread_mutex_init(&mutex, NULL); + // Create thread pool and run threads + pthread_t thread[2]; + pthread_create(&thread[i], NULL, &inc, NULL); + pthread_create(&thread[i + 1], NULL, &dec, NULL); + // Wait for threads to finish + pthread_join(thread[i], NULL); + pthread_join(thread[i + 1], NULL); + // Destroy Mutex + pthread_mutex_destroy(&mutex); + // Print final value + printf("%d\n", gv); + + // Init Semaphore + sem_init(&sem, 0, 0); + for (i = 0; i < 1; i++) { + unsigned int *t = (unsigned int *) malloc(sizeof(unsigned int)); + *t = rand(); + + pthread_create(&(thread[i]), NULL, &plus, (void *) t); + pthread_create(&(thread[i + 1]), NULL, &minus, NULL); + + pthread_join(thread[i], NULL); + pthread_join(thread[i + 1], NULL); + } + sem_destroy(&sem); + + return 0; +} +//TODO: Delete this comment +//Semaphore doesn't work because it increments the semaphore all at once before the other thread even gets the chance to print +//Just as an example to fix it you would need two semaphores so you can signal back and forth between the two threads \ No newline at end of file diff --git a/Lab4/documentation/Lab4.pdf b/Lab4/documentation/Lab4.pdf new file mode 100644 index 0000000..ee9251a Binary files /dev/null and b/Lab4/documentation/Lab4.pdf differ diff --git a/Lab4/run.sh b/Lab4/run.sh new file mode 100644 index 0000000..8b96d3d --- /dev/null +++ b/Lab4/run.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +while : + do + output=$(./build/Lab4) + if [ "$output" != "1" ]; then + echo "$output" + fi + done