Browse Source

week5

master
RinRi 1 year ago
parent
commit
c1fedb5946
21 changed files with 420 additions and 0 deletions
  1. +2
    -0
      week05/.clang-format
  2. BIN
      week05/channel
  3. +35
    -0
      week05/channel.c
  4. +21
    -0
      week05/ex1.sh
  5. BIN
      week05/ex2
  6. +38
    -0
      week05/ex2.c
  7. +4
    -0
      week05/ex2.sh
  8. BIN
      week05/ex3
  9. +93
    -0
      week05/ex3.c
  10. +8
    -0
      week05/ex3.explanation.txt
  11. +13
    -0
      week05/ex3.sh
  12. +15
    -0
      week05/ex3.txt
  13. BIN
      week05/ex4
  14. +85
    -0
      week05/ex4.c
  15. +12
    -0
      week05/ex4.explanation.txt
  16. +13
    -0
      week05/ex4.sh
  17. +15
    -0
      week05/ex4.txt
  18. BIN
      week05/publisher
  19. +43
    -0
      week05/publisher.c
  20. BIN
      week05/subscriber
  21. +23
    -0
      week05/subscriber.c

+ 2
- 0
week05/.clang-format View File

@@ -0,0 +1,2 @@
BasedOnStyle: LLVM
IndentWidth: 4

BIN
week05/channel View File


+ 35
- 0
week05/channel.c View File

@@ -0,0 +1,35 @@
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>

int main() {
int fd[2];
if (pipe(fd) == -1) {
perror("create pipe");
exit(1);
}

char mes[1024];
switch (fork()) {
case -1:
perror("fork");
exit(1);
case 0:
close(fd[1]);
read(fd[0], mes, 1024);
printf("%s\n", mes);
close(fd[0]);
break;
default:
close(fd[0]);
fgets(mes, 1024, stdin);
write(fd[1], mes, 1024);
close(fd[1]);
int status;
wait(&status);
}
}

+ 21
- 0
week05/ex1.sh View File

@@ -0,0 +1,21 @@
#!/bin/sh

if [ $# -ne 1 ]; then
printf "Usage: %s [subs]\n" "$0"
exit
fi

if [ -z "$TERMINAL" ]; then
TERMINAL=xterm
fi

gcc publisher.c -o publisher
gcc subscriber.c -o subscriber

$TERMINAL -e ./publisher "$1" &

i=0
while [ $i -lt "$1" ]; do
$TERMINAL -e ./subscriber &
i=$(( i + 1 ))
done

BIN
week05/ex2 View File


+ 38
- 0
week05/ex2.c View File

@@ -0,0 +1,38 @@
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>

typedef struct {
pthread_t id;
int i;
char mes[256];
} Thread;

void *print_thread(void *argv) {
Thread *t = argv;
printf("%d %s\n", t->i, t->mes);
pthread_exit(NULL);
return NULL;
}

int main(int argc, char **argv){
if (argc != 2) {
printf("Usage: %s [n]\n", argv[0]);
exit(1);
}

int n = atoi(argv[1]);

Thread threads[n];
for (int i = 0; i < n; ++i) {
threads[i].i = i;
snprintf(threads[i].mes, 256, "Hello from thread %d", i);
printf("Thread %d is created\n", i);
pthread_create(&threads[i].id, NULL, &print_thread, &threads[i]);
pthread_join(threads[i].id, NULL);
}
}

+ 4
- 0
week05/ex2.sh View File

@@ -0,0 +1,4 @@
#!/bin/sh

gcc ex2.c -o ex2 -pthread
./ex2 $1

BIN
week05/ex3 View File


+ 93
- 0
week05/ex3.c View File

@@ -0,0 +1,93 @@
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

int is_prime(int n) {
if (n <= 1)
return 0;
for (int d = 2; d * d <= n; d++)
if (n % d == 0)
return 0;
return 1;
}

int primes_count_in_interval(int start, int finish) {
int ret = 0;
for (int i = start; i < finish; i++)
if (is_prime(i) != 0)
ret++;
return ret;
}

// The structure that will be passed to the threads, corresponding to an
// interval to count the number of primes in.
typedef struct prime_counter_request {
int start, finish;
} prime_counter_request;

void *prime_counter(void *arg) {
/*
TODO
Complete this function. It takes a primes_counter_request as a parameter
and returns the number of primes in the specified interval. Be careful how
you return the return value.
*/
prime_counter_request *req = arg;
int *res = malloc(sizeof(int));
*res = primes_count_in_interval(req->start, req->finish);
return res;
}

int main(int argc, char *argv[]) {
int n = atoi(argv[1]), n_threads = atoi(argv[2]);
int segment_size = n / n_threads;

pthread_t *threads = malloc(n_threads * sizeof(pthread_t));

prime_counter_request *requests =
malloc(n_threads * sizeof(prime_counter_request));

void **results = malloc(n_threads * sizeof(void *));

for (int i = 0; i < n_threads; i++) {
/*
TODO
Complete this loop. You shall spawn <n_threads> threads, each of which
computes the number of primes in a segment of length <segment_size>.
The union of those intervals shall correspond to the interval [0, n).
First, initialize the value of requests[i] with a simple mathematical
computation. Be careful not to overrun the last interval. Second,
spawn a thread that takes requests[i] as an argument. Be careful how
you pass the arguments.
*/
requests[i].start = i * segment_size;
requests[i].finish = requests[i].start + segment_size;
if (requests[i].finish > n)
requests[i].finish = n;

pthread_create(&threads[i], NULL, &prime_counter, (void*) &requests[i]);
}

for (int i = 0; i < n_threads; i++) {
/*
TODO
Join the results of threads into the results array.
*/
pthread_join(threads[i], (void**) &results[i]);
}

int total_result = 0;
for (int i = 0; i < n_threads; i++)
total_result += *(int *)results[i];

/*
TODO
Free the allocated memory.
*/
for (int i = 0; i < n_threads; i++)
free(results[i]);

printf("%d\n", total_result);

exit(EXIT_SUCCESS);
}

+ 8
- 0
week05/ex3.explanation.txt View File

@@ -0,0 +1,8 @@
My machine has 4/8 cores

From results, improvement from 1->2 threads and 2->4 threads is almost 2 times,
but not exactly, since creating threads and joining them takes time as well.

When the number of threads is larger then the number of physical cores of my CPU,
e.g. 4->10 threads, 10->100 threads, the improvement is insignificant, since two
threads cannot run on the same core at the same time.

+ 13
- 0
week05/ex3.sh View File

@@ -0,0 +1,13 @@
#!/bin/sh

gcc ex3.c -o ex3
printf "time ./ex3 10000000 1\n" > ex3.txt
time ./ex3 10000000 1 2>> ex3.txt
printf "time ./ex3 10000000 2\n" >> ex3.txt
time ./ex3 10000000 2 2>> ex3.txt
printf "time ./ex3 10000000 4\n" >> ex3.txt
time ./ex3 10000000 4 2>> ex3.txt
printf "time ./ex3 10000000 10\n" >> ex3.txt
time ./ex3 10000000 10 2>> ex3.txt
printf "time ./ex3 10000000 100\n" >> ex3.txt
time ./ex3 10000000 100 2>> ex3.txt

+ 15
- 0
week05/ex3.txt View File

@@ -0,0 +1,15 @@
time ./ex3 10000000 1
10.82user 0.00system 0:10.88elapsed 99%CPU (0avgtext+0avgdata 1576maxresident)k
0inputs+0outputs (0major+75minor)pagefaults 0swaps
time ./ex3 10000000 2
11.17user 0.05system 0:07.02elapsed 159%CPU (0avgtext+0avgdata 1640maxresident)k
0inputs+0outputs (0major+78minor)pagefaults 0swaps
time ./ex3 10000000 4
11.66user 0.16system 0:03.95elapsed 298%CPU (0avgtext+0avgdata 3056maxresident)k
0inputs+0outputs (0major+86minor)pagefaults 0swaps
time ./ex3 10000000 10
20.34user 0.33system 0:03.04elapsed 679%CPU (0avgtext+0avgdata 3528maxresident)k
0inputs+0outputs (0major+105minor)pagefaults 0swaps
time ./ex3 10000000 100
22.07user 0.15system 0:02.98elapsed 744%CPU (0avgtext+0avgdata 5744maxresident)k
0inputs+0outputs (0major+348minor)pagefaults 0swaps

BIN
week05/ex4 View File


+ 85
- 0
week05/ex4.c View File

@@ -0,0 +1,85 @@
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

int is_prime(int n) {
if (n <= 1)
return 0;
for (int d = 2; d * d <= n; d++)
if (n % d == 0)
return 0;
return 1;
}

int n = 0;

// You will be locking and unlocking this
pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;

// Don't modify these variables directly, use the functions below.
int next_number_to_check = 0;
int primes_found_so_far = 0;

int get_number_to_check() {
int ret = next_number_to_check;
if (next_number_to_check != n)
next_number_to_check++;
return ret;
}

void increment_primes() { primes_found_so_far++; }

void *check_primes(void *arg) {
/*
TODO
Complete this function. This function loops forever, continuously taking a
value from get_number_to_check and, if it turns out to be prime,
increments the global prime counter with increment_primes. Once
get_number_to_check returns <n>, the function exits. Pay close attention
to your use of the global mutex.
*/
while(1) {
pthread_mutex_lock(&global_lock);
int num = get_number_to_check();
pthread_mutex_unlock(&global_lock);

if (is_prime(num)) {
pthread_mutex_lock(&global_lock);
increment_primes();
pthread_mutex_unlock(&global_lock);
}
if (num == n)
return NULL;
}
}

int main(int argc, char *argv[]) {
int n_threads = atoi(argv[2]);
n = atoi(argv[1]);

pthread_mutex_init(&global_lock, NULL);
pthread_t *threads = malloc(n_threads * sizeof(pthread_t));
for (int i = 0; i < n_threads; i++) {
/*
TODO
Spawn <n_threads> threads.
*/
pthread_create(&threads[i], NULL, &check_primes, NULL);
}
for (int i = 0; i < n_threads; i++) {
/*
TODO
Join the threads.
*/
pthread_join(threads[i], NULL);
}

/*
TODO
Free the allocated memory.
*/
pthread_mutex_destroy(&global_lock);

printf("%d\n", primes_found_so_far);
exit(EXIT_SUCCESS);
}

+ 12
- 0
week05/ex4.explanation.txt View File

@@ -0,0 +1,12 @@
The execution time is almost the same as ex3.
But, in this case, after increasing number of threads
4->10 and 10->100, the execution time is
insignificantly increasing. It is probably caused by
mutexes, since they don't allow multiple threads run
the locked code at the same time. The number of
threads is way higher than the number of physical
cores and the most of them don't even work at the same
time because of mutexes. The increased amount of
execution time is probably caused by the overheads of
threads and mutexes.


+ 13
- 0
week05/ex4.sh View File

@@ -0,0 +1,13 @@
#!/bin/sh

gcc ex4.c -o ex4
printf "time ./ex4 10000000 1\n" > ex4.txt
time ./ex4 10000000 1 2>> ex4.txt
printf "time ./ex4 10000000 2\n" >> ex4.txt
time ./ex4 10000000 2 2>> ex4.txt
printf "time ./ex4 10000000 4\n" >> ex4.txt
time ./ex4 10000000 4 2>> ex4.txt
printf "time ./ex4 10000000 10\n" >> ex4.txt
time ./ex4 10000000 10 2>> ex4.txt
printf "time ./ex4 10000000 100\n" >> ex4.txt
time ./ex4 10000000 100 2>> ex4.txt

+ 15
- 0
week05/ex4.txt View File

@@ -0,0 +1,15 @@
time ./ex4 10000000 1
10.27user 0.00system 0:10.36elapsed 99%CPU (0avgtext+0avgdata 1720maxresident)k
0inputs+0outputs (0major+78minor)pagefaults 0swaps
time ./ex4 10000000 2
10.65user 0.02system 0:05.38elapsed 198%CPU (0avgtext+0avgdata 1588maxresident)k
0inputs+0outputs (0major+76minor)pagefaults 0swaps
time ./ex4 10000000 4
12.35user 0.14system 0:03.15elapsed 396%CPU (0avgtext+0avgdata 1548maxresident)k
0inputs+0outputs (0major+80minor)pagefaults 0swaps
time ./ex4 10000000 10
20.43user 0.81system 0:03.25elapsed 652%CPU (0avgtext+0avgdata 1672maxresident)k
0inputs+0outputs (0major+98minor)pagefaults 0swaps
time ./ex4 10000000 100
20.05user 0.80system 0:03.28elapsed 634%CPU (0avgtext+0avgdata 2116maxresident)k
0inputs+0outputs (0major+281minor)pagefaults 0swaps

BIN
week05/publisher View File


+ 43
- 0
week05/publisher.c View File

@@ -0,0 +1,43 @@
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>

int main(int argc, char **argv) {
if (argc != 2) {
printf("Usage: %s [subs]", argv[0]);
exit(1);
}

printf("PUBLISHER\n");

int subs = atoi(argv[1]);

if (mkfifo("/tmp/ex1", 0777) == -1) {
if (errno != EEXIST) {
perror("mkfifo");
exit(1);
}
}

int fd = open("/tmp/ex1", O_WRONLY);
if (fd == -1) {
perror("open");
exit(1);
}

while(1) {
char mes[1024];
fgets(mes, 1024, stdin);

for (int i = 0; i < subs; ++i)
write(fd, mes, 1024);
sleep(1);
}
}

// mkfifo reference
// https://man7.org/linux/man-pages/man3/mkfifo.3.html

BIN
week05/subscriber View File


+ 23
- 0
week05/subscriber.c View File

@@ -0,0 +1,23 @@
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

int main() {
printf("SUBSCRIBER\n");

int fd = open("/tmp/ex1", O_RDONLY);
if (fd == -1) {
perror("open");
exit(1);
}

char mes[1024];
while(1) {
read(fd, mes, 1024);
printf("%s", mes);
sleep(1);
}
}

Loading…
Cancel
Save