From 4ad7a6d3ab8b6993f1fa773f0c982cd860a6767f Mon Sep 17 00:00:00 2001 From: Yury Kurlykov Date: Thu, 11 Jun 2020 15:00:19 +1000 Subject: [PATCH] Add 9th and 10th labs --- CMakeLists.txt | 4 +- lab10/.execme | 7 ++ lab10/CMakeLists.txt | 35 ++++++ lab10/README.md | 76 ++++++++++++ lab10/killer.c | 10 ++ lab10/reader.c | 21 ++++ lab9/.execme | 7 ++ lab9/CMakeLists.txt | 57 +++++++++ lab9/README.md | 231 ++++++++++++++++++++++++++++++++++++ lab9/main-deadlock-global.c | 31 +++++ lab9/main-deadlock.c | 28 +++++ lab9/main-race.c | 23 ++++ lab9/main-signal-cv.c | 56 +++++++++ lab9/main-signal.c | 20 ++++ lab9/mythread.h | 55 +++++++++ 15 files changed, 660 insertions(+), 1 deletion(-) create mode 100755 lab10/.execme create mode 100644 lab10/CMakeLists.txt create mode 100644 lab10/README.md create mode 100644 lab10/killer.c create mode 100644 lab10/reader.c create mode 100755 lab9/.execme create mode 100644 lab9/CMakeLists.txt create mode 100644 lab9/README.md create mode 100644 lab9/main-deadlock-global.c create mode 100644 lab9/main-deadlock.c create mode 100644 lab9/main-race.c create mode 100644 lab9/main-signal-cv.c create mode 100644 lab9/main-signal.c create mode 100644 lab9/mythread.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fdcc917..8768e6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,4 +18,6 @@ define_lab(lab3) define_lab(lab4) define_lab(lab5) define_lab(lab6) -define_lab(lab7) \ No newline at end of file +define_lab(lab7) +define_lab(lab9) +define_lab(lab10) \ No newline at end of file diff --git a/lab10/.execme b/lab10/.execme new file mode 100755 index 0000000..901d422 --- /dev/null +++ b/lab10/.execme @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -euo pipefail +IFS=$'\n\t' + +echo "TODO!" +exit 1 \ No newline at end of file diff --git a/lab10/CMakeLists.txt b/lab10/CMakeLists.txt new file mode 100644 index 0000000..09ee50f --- /dev/null +++ b/lab10/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.16) +set(CMAKE_C_STANDARD 11) + +# Lab name +set(LAB_NAME "lab10") + +# Lab tasks +list(APPEND SOURCE_FILES + killer.c + reader.c + ) +list(APPEND NON_COMPILABLE_SRC + .execme + ) + +### Here goes the template + +project("${LAB_NAME}" C) + +add_custom_target("${LAB_NAME}") + +foreach (file IN LISTS SOURCE_FILES) + add_executable("${LAB_NAME}_${file}_run" "${file}") + add_dependencies("${LAB_NAME}" "${LAB_NAME}_${file}_run") +endforeach () + +foreach (file IN LISTS NON_COMPILABLE_SRC) + add_custom_command( + TARGET "${LAB_NAME}" POST_BUILD + DEPENDS "${file}" + COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/${file}" + "${CMAKE_CURRENT_BINARY_DIR}/${file}" + ) +endforeach () \ No newline at end of file diff --git a/lab10/README.md b/lab10/README.md new file mode 100644 index 0000000..08c3048 --- /dev/null +++ b/lab10/README.md @@ -0,0 +1,76 @@ +# Лабораторная работа №10 + +## Задание 1 + +С операцией чтения ничего не произошло (она завершилась успешно), так как согласно документации: + +> if any process has the file open when this happens, deletion is postponed until all processes have closed the file. +> (https://www.gnu.org/software/libc/manual/html_node/Deleting-Files.html#Deleting-Files) + +## Задание 2 + +Герц = 1 с^(-1) + +2 000 000 * 4 = 8 000 000 - количество операций, необходимых для вычисления программы процессором. + +Тогда 8 000 000 / 8 000 000 Гц = 1 с. + +Т.е. для проведения данных вычислений нам нужна 1 секунда. + +## Задание 3 + +Так как виртуальный адрес состоит из номера страницы и смещения в ней, то: + +размер виртуального адреса в битах (обозначим за n) = количеству бит под номер страницы (p) ++ количество бит под смещение в странице (d) + +n = p + d + +p = n - d + +n = 20 (по условию) + +d = log2 (размера страницы) = log2 (1KB) = 10 + +p = 20 - 10 = 10 - количество бит отделяемых в виртуальном адресе под номер страницы. + +Тогда возможное число страниц: + +2^p = 2^10 = 1024 + +Ответ: 1024 элемента в таблице страниц. + +## Задание 4 + +[https://www.intuit.ru/studies/courses/641/497/lecture/11286?page=1](https://www.intuit.ru/studies/courses/641/497/lecture/11286?page=1) + +Рассмотрим алгоритмы диспетчеризации по следующим критериям: + +1. время ожидания +2. starvation +3. Время обработки процесса (turnaround time) +4. Разница во времени выполнения процесса + +### Алгоритмы: + +1. First-Come-First-Served (FCFS) + 1. Зависит от сложившейся ситуации. В большинстве случаев является не минимальным, так как не оптимизируется. + 2. Отсутствует + 3. Зависит от сложившейся ситуации. + 4. Зависит от порядка входа. +2. Shortest Job First (SJF) + 1. практически минимальное среднее время ожидания. + 2. возможно, для тяжёлых процессов. + 3. для длительных процессов время выполнение гораздо больше, чем в FCFS. + 4. отсутствует. +3. Shortest-Remaining-Time-First (SRTF) - SJF с прерыванием, если пришедший процесс выполнять быстрее чем текущий, то мы останавливаем его и берём новый. + 1. минимальное среднее время ожидания. + 2. возможно, для тяжёлых процессов, но не так сильно, как в SJF. + 3. для длительных процессов время выполнение гораздо больше, чем в SJF, так требует затраты на переключение, во время выполнения процесса. + 4. отсутствует. +4. Round Robin (RR) - даём всем процессам одинаковое время по очереди. + 1. для всех одинаковое. + 2. отсутствует. + 3. зависит от выбранного кванта, если он достаточно большой, то ситуация напоминает FCFS, если же сильно мал, то становятся значительными затраты на переключение процессов. + 4. зависит от выбранного кванта. + diff --git a/lab10/killer.c b/lab10/killer.c new file mode 100644 index 0000000..b981001 --- /dev/null +++ b/lab10/killer.c @@ -0,0 +1,10 @@ +#include +#include + +int main() { + if (unlink("test.txt") != 0) { + printf("Unlink error."); + return -1; + } + return 0; +} \ No newline at end of file diff --git a/lab10/reader.c b/lab10/reader.c new file mode 100644 index 0000000..daffc26 --- /dev/null +++ b/lab10/reader.c @@ -0,0 +1,21 @@ +#include + +int main() { + char c; + FILE *f = fopen("test.txt", "r"); // открыли файл + if (!f) { // проверили успешность открытия + printf("File not found."); + return -1; + } + + while (1) { + fseek(f, 0, SEEK_SET); + while ((c = fgetc(f)) != + EOF) { // считали символ, и проверили что он не конечный + printf("%c", c); // добавили XOR к ответу символа + } + } + + fclose(f); + return 0; +} \ No newline at end of file diff --git a/lab9/.execme b/lab9/.execme new file mode 100755 index 0000000..901d422 --- /dev/null +++ b/lab9/.execme @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -euo pipefail +IFS=$'\n\t' + +echo "TODO!" +exit 1 \ No newline at end of file diff --git a/lab9/CMakeLists.txt b/lab9/CMakeLists.txt new file mode 100644 index 0000000..8401db8 --- /dev/null +++ b/lab9/CMakeLists.txt @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 3.16) +set(CMAKE_C_STANDARD 11) + +# Lab name +set(LAB_NAME "lab9") + +# Lab tasks +#list(APPEND SOURCE_FILES +# task1.c +# task2.c +# mytail.c +# mystat.c +# myls.c +# task6.c +# ) +list(APPEND NON_COMPILABLE_SRC + .execme + ) + +### Here goes the template + +project("${LAB_NAME}" C) + +add_custom_target("${LAB_NAME}") + +#foreach (file IN LISTS SOURCE_FILES) +# add_executable("${LAB_NAME}_${file}_run" "${file}") +# add_dependencies("${LAB_NAME}" "${LAB_NAME}_${file}_run") +#endforeach () + +find_package (Threads) +add_executable(${LAB_NAME}_main-race_run main-race.c mythread.h) +add_executable(${LAB_NAME}_main-deadlock_run main-deadlock.c mythread.h) +add_executable(${LAB_NAME}_main-deadlock-global_run main-deadlock-global.c mythread.h) +add_executable(${LAB_NAME}_main-signal_run main-signal.c mythread.h) +add_executable(${LAB_NAME}_main-signal-cv_run main-signal-cv.c mythread.h) +target_link_libraries (${LAB_NAME}_main-race_run ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (${LAB_NAME}_main-deadlock_run ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (${LAB_NAME}_main-deadlock-global_run ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (${LAB_NAME}_main-signal_run ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (${LAB_NAME}_main-signal-cv_run ${CMAKE_THREAD_LIBS_INIT}) + +add_dependencies("${LAB_NAME}" ${LAB_NAME}_main-race_run) +add_dependencies("${LAB_NAME}" ${LAB_NAME}_main-deadlock_run) +add_dependencies("${LAB_NAME}" ${LAB_NAME}_main-deadlock-global_run) +add_dependencies("${LAB_NAME}" ${LAB_NAME}_main-signal_run) +add_dependencies("${LAB_NAME}" ${LAB_NAME}_main-signal-cv_run) + +foreach (file IN LISTS NON_COMPILABLE_SRC) + add_custom_command( + TARGET "${LAB_NAME}" POST_BUILD + DEPENDS "${file}" + COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/${file}" + "${CMAKE_CURRENT_BINARY_DIR}/${file}" + ) +endforeach () \ No newline at end of file diff --git a/lab9/README.md b/lab9/README.md new file mode 100644 index 0000000..1e63daf --- /dev/null +++ b/lab9/README.md @@ -0,0 +1,231 @@ +# Лабораторная работа №9 + +## Задание 2 + +Команда запуска: + +`valgrind --tool=helgrind ./lab9_main-race_run` + +Результат: + +```text +... +==4862== Possible data race during read of size 4 at 0x30A014 by thread #1 +==4862== Locks held: none +==4862== at 0x108D27: main (main-race.c:15) +==4862== +==4862== This conflicts with a previous write of size 4 by thread #2 +==4862== Locks held: none +==4862== at 0x108CDF: worker (main-race.c:8) +==4862== by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==4862== by 0x4E496DA: start_thread (pthread_create.c:463) +==4862== by 0x518288E: clone (clone.S:95) +==4862== Address 0x30a014 is 0 bytes inside data symbol "balance" +... +``` + +helgrind сообщает, что возможно использование переменной balance в двух потоках параллельно. + +### Решение проблемы: + +Блокировать незащищенный процесс. + +Заменить: +```c +balance++; +``` + +на: +```c +Pthread_mutex_lock(&m); // блокировка мьютекса +balance++; +Pthread_mutex_unlock(&m); // разблокировка +``` + + +## Задание 3 + +Команда запуска: + +`valgrind --tool=helgrind ./lab9_main-deadlock_run` + +Результат: + +```text +... +==6272== Thread #3: lock order "0x30A040 before 0x30A080" violated +==6272== +==6272== Observed (incorrect) order is: acquisition of lock at 0x30A080 +==6272== at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==6272== by 0x108AD7: Pthread_mutex_lock (mythreads.h:23) +==6272== by 0x108D06: worker (main-deadlock.c:13) +==6272== by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==6272== by 0x4E496DA: start_thread (pthread_create.c:463) +==6272== by 0x518288E: clone (clone.S:95) +==6272== +==6272== followed by a later acquisition of lock at 0x30A040 +==6272== at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==6272== by 0x108AD7: Pthread_mutex_lock (mythreads.h:23) +==6272== by 0x108D12: worker (main-deadlock.c:14) +==6272== by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==6272== by 0x4E496DA: start_thread (pthread_create.c:463) +==6272== by 0x518288E: clone (clone.S:95) +==6272== +==6272== Required order was established by acquisition of lock at 0x30A040 +==6272== at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==6272== by 0x108AD7: Pthread_mutex_lock (mythreads.h:23) +==6272== by 0x108CEC: worker (main-deadlock.c:10) +==6272== by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==6272== by 0x4E496DA: start_thread (pthread_create.c:463) +==6272== by 0x518288E: clone (clone.S:95) +==6272== +==6272== followed by a later acquisition of lock at 0x30A080 +==6272== at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==6272== by 0x108AD7: Pthread_mutex_lock (mythreads.h:23) +==6272== by 0x108CF8: worker (main-deadlock.c:11) +==6272== by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==6272== by 0x4E496DA: start_thread (pthread_create.c:463) +==6272== by 0x518288E: clone (clone.S:95) +==6272== +==6272== Lock at 0x30A040 was first observed +==6272== at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==6272== by 0x108AD7: Pthread_mutex_lock (mythreads.h:23) +==6272== by 0x108CEC: worker (main-deadlock.c:10) +==6272== by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==6272== by 0x4E496DA: start_thread (pthread_create.c:463) +==6272== by 0x518288E: clone (clone.S:95) +==6272== Address 0x30a040 is 0 bytes inside data symbol "m1" +==6272== +==6272== Lock at 0x30A080 was first observed +==6272== at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==6272== by 0x108AD7: Pthread_mutex_lock (mythreads.h:23) +==6272== by 0x108CF8: worker (main-deadlock.c:11) +==6272== by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==6272== by 0x4E496DA: start_thread (pthread_create.c:463) +==6272== by 0x518288E: clone (clone.S:95) +==6272== Address 0x30a080 is 0 bytes inside data symbol "m2" +... +``` + +helgrind сообщает, что блокировка мьютексов происходит в неправильном порядке. + +## Задание 4 + +Команда запуска: + +`valgrind --tool=helgrind ./lab9_main-deadlock-global_run` + +Результат: +```text +... +==7133== Thread #3: lock order "0x30A080 before 0x30A0C0" violated +==7133== +==7133== Observed (incorrect) order is: acquisition of lock at 0x30A0C0 +==7133== at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==7133== by 0x108AD7: Pthread_mutex_lock (mythreads.h:23) +==7133== by 0x108D12: worker (main-deadlock-global.c:15) +==7133== by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==7133== by 0x4E496DA: start_thread (pthread_create.c:463) +==7133== by 0x518288E: clone (clone.S:95) +==7133== +==7133== followed by a later acquisition of lock at 0x30A080 +==7133== at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==7133== by 0x108AD7: Pthread_mutex_lock (mythreads.h:23) +==7133== by 0x108D1E: worker (main-deadlock-global.c:16) +==7133== by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==7133== by 0x4E496DA: start_thread (pthread_create.c:463) +==7133== by 0x518288E: clone (clone.S:95) +==7133== +==7133== Required order was established by acquisition of lock at 0x30A080 +==7133== at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==7133== by 0x108AD7: Pthread_mutex_lock (mythreads.h:23) +==7133== by 0x108CF8: worker (main-deadlock-global.c:12) +==7133== by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==7133== by 0x4E496DA: start_thread (pthread_create.c:463) +==7133== by 0x518288E: clone (clone.S:95) +==7133== +==7133== followed by a later acquisition of lock at 0x30A0C0 +==7133== at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==7133== by 0x108AD7: Pthread_mutex_lock (mythreads.h:23) +==7133== by 0x108D04: worker (main-deadlock-global.c:13) +==7133== by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==7133== by 0x4E496DA: start_thread (pthread_create.c:463) +==7133== by 0x518288E: clone (clone.S:95) +==7133== +==7133== Lock at 0x30A080 was first observed +==7133== at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==7133== by 0x108AD7: Pthread_mutex_lock (mythreads.h:23) +==7133== by 0x108CF8: worker (main-deadlock-global.c:12) +==7133== by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==7133== by 0x4E496DA: start_thread (pthread_create.c:463) +==7133== by 0x518288E: clone (clone.S:95) +==7133== Address 0x30a080 is 0 bytes inside data symbol "m1" +==7133== +==7133== Lock at 0x30A0C0 was first observed +==7133== at 0x4C3403C: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==7133== by 0x108AD7: Pthread_mutex_lock (mythreads.h:23) +==7133== by 0x108D04: worker (main-deadlock-global.c:13) +==7133== by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==7133== by 0x4E496DA: start_thread (pthread_create.c:463) +==7133== by 0x518288E: clone (clone.S:95) +==7133== Address 0x30a0c0 is 0 bytes inside data symbol "m2" +... +``` + +helgrind сообщает об аналогичной ошибке 3 заданию, тогда как она отсутствует, так как дополнительный мьютекс не допускает такую ситуацию. + +## Задание 5 + +Команда запуска: + +`valgrind --tool=helgrind ./lab9_main-signal_run` + +Результат: + +```text +... +==7499== Possible data race during write of size 4 at 0x30A014 by thread #2 +==7499== Locks held: none +==7499== at 0x108D36: worker (main-signal.c:9) +==7499== by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so) +==7499== by 0x4E496DA: start_thread (pthread_create.c:463) +==7499== by 0x518288E: clone (clone.S:95) +==7499== +==7499== This conflicts with a previous read of size 4 by thread #1 +==7499== Locks held: none +==7499== at 0x108D83: main (main-signal.c:16) +==7499== Address 0x30a014 is 0 bytes inside data symbol "done" +... +``` + +helgrind сообщает о возможном одновременном использовании переменной done. + +Такой метод ожидания потока не является эффективным, так как: + +- может наступить чтение в момент записи +- требует дополнительных затрат ожидающего потока. + +Наиболее эффективно было бы использовать мьютексы. + +## Задание 6 + + + +Команда запуска: + +`valgrind --tool=helgrind ./lab9_main-signal-cv_run` + + + +Результат: + +```text +... +==9132== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 7 from 7) +... +``` + +helgrind не удалось обнаружить ошибок. + +По сравнению с прошлой программой данная более эффективна, так как она не производит постоянный опрос, +а ожидает возвращение cond, и более безопасна для данных. diff --git a/lab9/main-deadlock-global.c b/lab9/main-deadlock-global.c new file mode 100644 index 0000000..30b51f3 --- /dev/null +++ b/lab9/main-deadlock-global.c @@ -0,0 +1,31 @@ +#include + +#include "mythread.h" + +pthread_mutex_t g = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; + +void* worker(void* arg) { + Pthread_mutex_lock(&g); + if ((long long) arg == 0) { + Pthread_mutex_lock(&m1); + Pthread_mutex_lock(&m2); + } else { + Pthread_mutex_lock(&m2); + Pthread_mutex_lock(&m1); + } + Pthread_mutex_unlock(&m1); + Pthread_mutex_unlock(&m2); + Pthread_mutex_unlock(&g); + return NULL; +} + +int main(int argc, char *argv[]) { + pthread_t p1, p2; + Pthread_create(&p1, NULL, worker, (void *) (long long) 0); + Pthread_create(&p2, NULL, worker, (void *) (long long) 1); + Pthread_join(p1, NULL); + Pthread_join(p2, NULL); + return 0; +} \ No newline at end of file diff --git a/lab9/main-deadlock.c b/lab9/main-deadlock.c new file mode 100644 index 0000000..8e6773f --- /dev/null +++ b/lab9/main-deadlock.c @@ -0,0 +1,28 @@ +#include + +#include "mythread.h" + +pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; + +void* worker(void* arg) { + if ((long long) arg == 0) { + Pthread_mutex_lock(&m1); + Pthread_mutex_lock(&m2); + } else { + Pthread_mutex_lock(&m2); + Pthread_mutex_lock(&m1); + } + Pthread_mutex_unlock(&m1); + Pthread_mutex_unlock(&m2); + return NULL; +} + +int main(int argc, char *argv[]) { + pthread_t p1, p2; + Pthread_create(&p1, NULL, worker, (void *) (long long) 0); + Pthread_create(&p2, NULL, worker, (void *) (long long) 1); + Pthread_join(p1, NULL); + Pthread_join(p2, NULL); + return 0; +} \ No newline at end of file diff --git a/lab9/main-race.c b/lab9/main-race.c new file mode 100644 index 0000000..974aac1 --- /dev/null +++ b/lab9/main-race.c @@ -0,0 +1,23 @@ +#include + +#include "mythread.h" + +pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; +int balance = 0; + +void *worker(void *arg) { + Pthread_mutex_lock(&m); + balance++; + Pthread_mutex_unlock(&m); + return NULL; +} + +int main(int argc, char *argv[]) { + pthread_t p; + Pthread_create(&p, NULL, worker, NULL); + Pthread_mutex_lock(&m); // блокировка мютекса + balance++; + Pthread_mutex_unlock(&m); // разблокировка + Pthread_join(p, NULL); + return 0; +} \ No newline at end of file diff --git a/lab9/main-signal-cv.c b/lab9/main-signal-cv.c new file mode 100644 index 0000000..3d18075 --- /dev/null +++ b/lab9/main-signal-cv.c @@ -0,0 +1,56 @@ + +#include + +#include "mythread.h" + +// +// simple synchronizer: allows one thread to wait for another +// structure "synchronizer_t" has all the needed data +// methods are: +// init (called by one thread) +// wait (to wait for a thread) +// done (to indicate thread is done) +// +typedef struct __synchronizer_t { + pthread_mutex_t lock; + pthread_cond_t cond; + int done; +} synchronizer_t; + +synchronizer_t s; + +void signal_init(synchronizer_t *s) { + Pthread_mutex_init(&s->lock, NULL); + Pthread_cond_init(&s->cond, NULL); + s->done = 0; +} + +void signal_done(synchronizer_t *s) { + Pthread_mutex_lock(&s->lock); + s->done = 1; + Pthread_cond_signal(&s->cond); + Pthread_mutex_unlock(&s->lock); +} + +void signal_wait(synchronizer_t *s) { + Pthread_mutex_lock(&s->lock); + while (s->done == 0) + Pthread_cond_wait(&s->cond, &s->lock); + Pthread_mutex_unlock(&s->lock); +} + +void* worker(void* arg) { + printf("this should print first\n"); + signal_done(&s); + return NULL; +} + +int main(int argc, char *argv[]) { + pthread_t p; + signal_init(&s); + Pthread_create(&p, NULL, worker, NULL); + signal_wait(&s); + printf("this should print last\n"); + + return 0; +} \ No newline at end of file diff --git a/lab9/main-signal.c b/lab9/main-signal.c new file mode 100644 index 0000000..a55199c --- /dev/null +++ b/lab9/main-signal.c @@ -0,0 +1,20 @@ +#include + +#include "mythread.h" + +int done = 0; + +void* worker(void* arg) { + printf("this should print first\n"); + done = 1; + return NULL; +} + +int main(int argc, char *argv[]) { + pthread_t p; + Pthread_create(&p, NULL, worker, NULL); + while (done == 0) + ; + printf("this should print last\n"); + return 0; +} \ No newline at end of file diff --git a/lab9/mythread.h b/lab9/mythread.h new file mode 100644 index 0000000..18557a6 --- /dev/null +++ b/lab9/mythread.h @@ -0,0 +1,55 @@ +#include +#include +#include +#include + +double Time_GetSeconds() { + struct timeval t; + int rc = gettimeofday(&t, NULL); + assert(rc == 0); + return (double) ((double)t.tv_sec + (double)t.tv_usec / 1e6); +} + +void Pthread_mutex_init(pthread_mutex_t *mutex, + const pthread_mutexattr_t *attr) { + int rc = pthread_mutex_init(mutex, attr); + assert(rc == 0); +} + +void Pthread_mutex_lock(pthread_mutex_t *m) { + int rc = pthread_mutex_lock(m); + assert(rc == 0); +} + +void Pthread_mutex_unlock(pthread_mutex_t *m) { + int rc = pthread_mutex_unlock(m); + assert(rc == 0); +} + +void Pthread_cond_init(pthread_cond_t *cond, + const pthread_condattr_t *attr) { + int rc = pthread_cond_init(cond, attr); + assert(rc == 0); +} + +void Pthread_cond_wait(pthread_cond_t *cond, + pthread_mutex_t *mutex) { + int rc = pthread_cond_wait(cond, mutex); + assert(rc == 0); +} + +void Pthread_cond_signal(pthread_cond_t *cond) { + int rc = pthread_cond_signal(cond); + assert(rc == 0); +} + +void Pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void*), void *arg) { + int rc = pthread_create(thread, attr, start_routine, arg); + assert(rc == 0); +} + +void Pthread_join(pthread_t thread, void **value_ptr) { + int rc = pthread_join(thread, value_ptr); + assert(rc == 0); +}