Меняется значение элемента массива на число, которое в него не записывали
Есть два потока, один записывает в циклический буффер, другой считывает. Синхронизация делается с использование мьютексов. Вроде работает всё правильно, НО почему то в ячейку записывается одно число, а выводится другое (см. изображение). Не понимаю почему это происходит, т. к. нигде после записи данные в массиве не изменяются. При этом до вывода значения ячейки, в неё записывается 0, но выводится 3995. Помогите, пожалуйста понять, почему это происходит.
#include <pthread.h>
#include <stdio.h> // printf, scanf
#include <unistd.h>
#include <stdlib.h>
#define BUFFER_SIZE 15
pthread_mutex_t my_sync;
pthread_cond_t cond_write;
pthread_cond_t cond_read;
pthread_t thread_write;
pthread_t thread_read;
int buffer[BUFFER_SIZE];
int *ptr_read = (int *)buffer;
int *ptr_write = (int *)buffer;
int *ptr_end = (int *)buffer + BUFFER_SIZE - 1;
int *ptr_start = (int *)buffer;
int number_write = 0;
int is_empty = 1;
int is_full = 0;
int my_sleep(int t)
{
return usleep(t * 1000000);
}
double t_rand(double min, double max)
{
double range = (max - min);
double div = RAND_MAX / range;
return min + (rand() / div);
}
void *func_write()
{
while(1)
{
while (is_full) pthread_cond_wait(&cond_write, &thread_write);
pthread_mutex_lock(&my_sync);
*ptr_write = number_write;
printf("WRITE %d in %p. is_full=%d, is_empty=%d\n", *ptr_write, ptr_write, is_full, is_empty);
number_write++;
if (number_write == 10) number_write = 0;
if (ptr_write == ptr_end) ptr_write = ptr_start;
else ptr_write++;
is_full = ptr_write + 1 == ptr_read? 1: 0;
is_empty = ptr_read + 1 == ptr_write? 1: 0;
if (!is_empty) pthread_cond_signal(&cond_read);
pthread_mutex_unlock(&my_sync);
double t_sleep = t_rand(0.5, 2.0);
my_sleep(t_sleep);
}
}
void *func_read()
{
while(1)
{
while (is_empty) pthread_cond_wait(&cond_read, &thread_read);
pthread_mutex_lock(&my_sync);
printf("READ %d from %p. is_full=%d, is_empty=%d\n", *ptr_read, ptr_read, is_full, is_empty);
if (ptr_read == ptr_end) ptr_read = ptr_start;
else ptr_read++;
is_full = ptr_write + 1 == ptr_read? 1: 0;
is_empty = ptr_read + 1 == ptr_write? 1: 0;
if (!is_full) pthread_cond_signal(&cond_write);
pthread_mutex_unlock(&my_sync);
double t_sleep = t_rand(0.5, 2.0);
my_sleep(t_sleep);
}
}
int main()
{
srand(time(NULL));
pthread_mutex_init(&my_sync, NULL);
pthread_cond_init(&cond_write, NULL);
pthread_cond_init(&cond_read, NULL);
pthread_create(&thread_write, NULL, func_write, NULL);
pthread_create(&thread_read, NULL, func_read, NULL);
pthread_join(thread_write, NULL);
pthread_join(thread_read, NULL);
}
Ответы (1 шт):
Попробуем запустить ваш код в onlinegdb
:
main.c: In function ‘func_write’:
main.c:52:48: warning: passing argument 2 of ‘pthread_cond_wait’ from incompatible pointer type [-Wincompatible-pointer-types]
52 | while (is_full) pthread_cond_wait(&cond_write, &thread_write);
| ^~~~~~~~~~~~~
| |
| pthread_t * {aka long unsigned int *}
In file included from main.c:9:
/usr/include/pthread.h:1134:59: note: expected ‘pthread_mutex_t * restrict’ but argument is of type ‘pthread_t *’ {aka ‘long unsigned int *’}
1134 | pthread_mutex_t *__restrict __mutex)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
Тут явно написано, что вы передаёте аргумент типа pthread_t
там, где ожидается аргумент типа pthread_mutex_t
. Поэтому у вас никакой синхронизации и не происходит. Заведём собственно мьютексы и передадим их:
pthread_mutex_t thread_mutex_write;
pthread_mutex_t thread_mutex_read;
...
while (is_full) pthread_cond_wait(&cond_write, &thread_mutex_write);
^^^^^^^^^^^^^^^^^^^
...
while (is_empty) pthread_cond_wait(&cond_read, &thread_mutex_read);
^^^^^^^^^^^^^^^^^^
Теперь всё работает как положено:
WRITE 0 in 0x563b7734c1a0. is_full=0, is_empty=1
WRITE 1 in 0x563b7734c1a4. is_full=0, is_empty=1
READ 0 from 0x563b7734c1a0. is_full=0, is_empty=0
WRITE 2 in 0x563b7734c1a8. is_full=0, is_empty=1
READ 1 from 0x563b7734c1a4. is_full=0, is_empty=0
WRITE 3 in 0x563b7734c1ac. is_full=0, is_empty=1
WRITE 4 in 0x563b7734c1b0. is_full=0, is_empty=0
READ 2 from 0x563b7734c1a8. is_full=0, is_empty=0
WRITE 5 in 0x563b7734c1b4. is_full=0, is_empty=0
READ 3 from 0x563b7734c1ac. is_full=0, is_empty=0
READ 4 from 0x563b7734c1b0. is_full=0, is_empty=0
...
Я C++
не очень хорошо помню, возможно там ещё где-то ошибки есть, но по крайней мере теперь читает корректно.