Add 9th and 10th labs

master
Yury Kurlykov 2020-06-11 15:00:19 +10:00
parent 9e82285e43
commit 4ad7a6d3ab
Signed by: t1meshift
GPG Key ID: B133F3167ABF94D8
15 changed files with 660 additions and 1 deletions

View File

@ -18,4 +18,6 @@ define_lab(lab3)
define_lab(lab4)
define_lab(lab5)
define_lab(lab6)
define_lab(lab7)
define_lab(lab7)
define_lab(lab9)
define_lab(lab10)

7
lab10/.execme Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
echo "TODO!"
exit 1

35
lab10/CMakeLists.txt Normal file
View File

@ -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 ()

76
lab10/README.md Normal file
View File

@ -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. зависит от выбранного кванта.

10
lab10/killer.c Normal file
View File

@ -0,0 +1,10 @@
#include <stdio.h>
#include <unistd.h>
int main() {
if (unlink("test.txt") != 0) {
printf("Unlink error.");
return -1;
}
return 0;
}

21
lab10/reader.c Normal file
View File

@ -0,0 +1,21 @@
#include <stdio.h>
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;
}

7
lab9/.execme Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
echo "TODO!"
exit 1

57
lab9/CMakeLists.txt Normal file
View File

@ -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 ()

231
lab9/README.md Normal file
View File

@ -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, и более безопасна для данных.

View File

@ -0,0 +1,31 @@
#include <stdio.h>
#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;
}

28
lab9/main-deadlock.c Normal file
View File

@ -0,0 +1,28 @@
#include <stdio.h>
#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;
}

23
lab9/main-race.c Normal file
View File

@ -0,0 +1,23 @@
#include <stdio.h>
#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;
}

56
lab9/main-signal-cv.c Normal file
View File

@ -0,0 +1,56 @@
#include <stdio.h>
#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;
}

20
lab9/main-signal.c Normal file
View File

@ -0,0 +1,20 @@
#include <stdio.h>
#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;
}

55
lab9/mythread.h Normal file
View File

@ -0,0 +1,55 @@
#include <pthread.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/time.h>
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);
}