#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;
}