#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define Thrd_return_t void *
#define __USE_XOPEN2K8
#define COUNT_LIMIT 5
static void fatal_error(void)
{
exit(1);
}
pthread_mutex_t mutex1;
pthread_mutex_t mutex2;
pthread_mutex_t mutex3;
pthread_cond_t cv;
int count1 = 0, count2 = 0, count3 = 0;
#define DELAY 8
Thrd_return_t waiter1(void* arg)
{
int ret;
while (count1 < COUNT_LIMIT) {
if ((ret = pthread_mutex_lock(&mutex1)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret =
pthread_cond_wait(&cv, &mutex1)) != 0) {
/* Handle error */
fatal_error();
}
sleep(random() % DELAY);
printf("count1 = %d\n", ++count1);
if ((ret = pthread_mutex_unlock(&mutex1)) != 0) {
/* Handle error */
fatal_error();
}
}
return (Thrd_return_t)0;
}
Thrd_return_t waiter2(void* arg)
{
int ret;
while (count2 < COUNT_LIMIT) {
if ((ret = pthread_mutex_lock(&mutex2)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret =
pthread_cond_wait(&cv, &mutex2)) != 0) {
/* Handle error */
fatal_error();
}
sleep(random() % DELAY);
printf("count2 = %d\n", ++count2);
if ((ret = pthread_mutex_unlock(&mutex2)) != 0) {
/* Handle error */
fatal_error();
}
}
return (Thrd_return_t)0;
}
Thrd_return_t signaler(void* arg)
{
int ret;
while ((count1 < COUNT_LIMIT) || (count2 < COUNT_LIMIT)) {
sleep(1);
printf("signaling\n");
if ((ret = pthread_cond_broadcast(&cv)) != 0) {
/* Handle error */
fatal_error();
}
}
return (Thrd_return_t)0;
}
Thrd_return_t waiter3(void* arg)
{
int ret;
while (count3 % COUNT_LIMIT != 0) {
if ((ret = pthread_mutex_lock(&mutex3)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret =
pthread_cond_wait(&cv, &mutex3)) != 0) {
/* Handle error */
fatal_error();
}
sleep(random() % DELAY);
printf("count3 = %d\n", ++count3);
if ((ret = pthread_mutex_unlock(&mutex3)) != 0) {
/* Handle error */
fatal_error();
}
}
return (Thrd_return_t)0;
}
int main(void)
{
int ret;
pthread_t thread1, thread2, thread3;
pthread_mutexattr_t attr;
if ((ret = pthread_mutexattr_init(&attr)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_mutex_init(&mutex1, &attr)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_mutex_init(&mutex2, &attr)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_mutex_init(&mutex3, &attr)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_cond_init(&cv, NULL)) != 0) {
/* handle error */
fatal_error();
}
if ((ret = pthread_create(&thread1, NULL, &waiter1, NULL))) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_create(&thread2, NULL, &waiter2, NULL))) {
/* handle error */
fatal_error();
}
if ((ret = pthread_create(&thread3, NULL, &signaler, NULL))) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_join(thread1, NULL)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_join(thread2, NULL)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_join(thread3, NULL)) != 0) {
/* Handle error */
fatal_error();
}
while (1) { ; }
return 0;
}
В этом примере различное взаимное исключение используется, чтобы защитить каждый count
переменная. Начиная со всех трех waiter
функции ожидают на той же условной переменной cv
с различными взаимными исключениями, вызовом pthread_cond_wait
успешно выполнится для одного из потоков, и вызов будет не определен для других двух.
Средство проверки повышает дефект для функционального waiter3
даже при том, что функция не вызывается прямо или косвенно потоком, точкой входа или прерыванием. Анализ рассматривает функциональный waiter3
вызванный основной программой через ее функциональный адрес или неопознанный поток, создание которого является недостающим исходным кодом.
Коррекция — использует то же взаимное исключение во всех потоках, ожидающих на той же условной переменной
Одна возможная коррекция должна передать тот же взаимоисключающий аргумент всему вызову pthread_cond_wait
это используется, чтобы ожидать на той же условной переменной.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define Thrd_return_t void *
#define __USE_XOPEN2K8
#define COUNT_LIMIT 5
static void fatal_error(void)
{
exit(1);
}
pthread_mutex_t mutex;
pthread_cond_t cv;
int count1 = 0, count2 = 0, count3 = 0;
#define DELAY 8
Thrd_return_t waiter1(void* arg)
{
int ret;
while (count1 < COUNT_LIMIT) {
if ((ret = pthread_mutex_lock(&mutex)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret =
pthread_cond_wait(&cv, &mutex)) != 0) {
/* Handle error */
fatal_error();
}
sleep(random() % DELAY);
printf("count1 = %d\n", ++count1);
if ((ret = pthread_mutex_unlock(&mutex)) != 0) {
/* Handle error */
fatal_error();
}
}
return (Thrd_return_t)0;
}
Thrd_return_t waiter2(void* arg)
{
int ret;
while (count2 < COUNT_LIMIT) {
if ((ret = pthread_mutex_lock(&mutex)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret =
pthread_cond_wait(&cv, &mutex)) != 0) {
/* Handle error */
fatal_error();
}
sleep(random() % DELAY);
printf("count2 = %d\n", ++count2);
if ((ret = pthread_mutex_unlock(&mutex)) != 0) {
/* Handle error */
fatal_error();
}
}
return (Thrd_return_t)0;
}
Thrd_return_t signaler(void* arg)
{
int ret;
while ((count1 < COUNT_LIMIT) || (count2 < COUNT_LIMIT)) {
sleep(1);
printf("signaling\n");
if ((ret = pthread_cond_broadcast(&cv)) != 0) {
/* Handle error */
fatal_error();
}
}
return (Thrd_return_t)0;
}
Thrd_return_t waiter3(void* arg)
{
int ret;
while (count3 % COUNT_LIMIT != 0) {
if ((ret = pthread_mutex_lock(&mutex)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret =
pthread_cond_wait(&cv, &mutex)) != 0) {
/* Handle error */
fatal_error();
}
sleep(random() % DELAY);
printf("count3 = %d\n", ++count3);
if ((ret = pthread_mutex_unlock(&mutex)) != 0) {
/* Handle error */
fatal_error();
}
}
return (Thrd_return_t)0;
}
/*
void user_task(void)
{
(void)waiter3(NULL);
} */
int main(void)
{
int ret;
pthread_t thread1, thread2, thread3;
pthread_mutexattr_t attr;
if ((ret = pthread_mutexattr_init(&attr)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_mutex_init(&mutex, &attr)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_mutex_init(&mutex, &attr)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_mutex_init(&mutex, &attr)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_cond_init(&cv, NULL)) != 0) {
/* handle error */
fatal_error();
}
if ((ret = pthread_create(&thread1, NULL, &waiter1, NULL))) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_create(&thread2, NULL, &waiter2, NULL))) {
/* handle error */
fatal_error();
}
if ((ret = pthread_create(&thread3, NULL, &signaler, NULL))) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_join(thread1, NULL)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_join(thread2, NULL)) != 0) {
/* Handle error */
fatal_error();
}
if ((ret = pthread_join(thread3, NULL)) != 0) {
/* Handle error */
fatal_error();
}
while (1) { ; }
return 0;
}