Значение семафора в функции внутри функции потока несовместимо

Я изучаю, как использовать pthreads и мьютексы, и меня смущает вывод следующего кода C:

#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>

void *TestThread(void *);
void TestFunc();

sem_t mutex;

int main(int argc, char *argv[]) {
    pthread_t tid;
    sem_init(&mutex, 1, 0);
    pthread_create(&tid, NULL, TestThread, NULL);
    pthread_join(tid, NULL);
}

void *TestThread(void *arg) {
    int val;
    sem_getvalue(&mutex, &val);
    printf("value of mutex in Thread function: %d\n", val);
    TestFunc();
    pthread_exit(NULL);
}

void TestFunc() {
    int val;
    sem_getvalue(&mutex, &val);
    printf("value of mutex in function in Thread function: %d\n", val);
}

Затем я компилирую это как g++ -lpthread mutexTest.c -o mutexTest и запускаю с ./mutexText, что дает и выводит как

value of mutex in Thread function: 0
value of mutex in function in Thread function: 1754151134

Почему значение мьютекса изменяется в функции, которую я вызываю в потоке? Я как-то потерял ссылку на мьютекс?


person TheStrangeQuark    schedule 12.03.2019    source источник
comment
Невозможно воспроизвести. Код выглядит нормально для меня навскидку.   -  person ggorlen    schedule 13.03.2019
comment
У меня тоже не получилось воспроизвести, но просто для устранения одной возможной проблемы попробуйте sem_init(&mutex, 0, 0);. Если это изменит поведение, сообщите нам об этом.   -  person thb    schedule 13.03.2019
comment
что произойдет, если вы скомпилируете с помощью компилятора C, такого как gcc, вместо компилятора C++?   -  person bruceg    schedule 13.03.2019
comment
@thb Внесение этого изменения дает те же результаты   -  person TheStrangeQuark    schedule 13.03.2019
comment
@bruceg Компиляция с помощью gcc дает те же результаты   -  person TheStrangeQuark    schedule 13.03.2019
comment
+1 Других потенциальных проблем не замечаю. Интересно. Как и вы, я буду рад прочитать ответ, когда он появится.   -  person thb    schedule 13.03.2019
comment
Какую операционную систему и версию gcc вы используете?   -  person bruceg    schedule 13.03.2019
comment
@bruceg MacOS Mojave 10.14.2, gcc и g++ говорят Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 Apple LLVM version 10.0.0 (clang-1000.10.44.4) Target: x86_64-apple-darwin18.2.0 Thread model: posix InstalledDir: /Library/Developer/CommandLineTools/usr/bin   -  person TheStrangeQuark    schedule 13.03.2019
comment
да ... в MacOS gcc и g++ оба являются псевдонимами для комплекта компилятора Mac. Я не могу воспроизвести на своем Linux-боксе. Надеюсь, у кого-то еще есть Mac.   -  person bruceg    schedule 13.03.2019
comment
Что sem_getvalue() возвращает в обоих случаях? Если он возвращает ненулевое значение, что такое errno? sem_getvalue() на Mac кажется проблематичным. См. раздел stackoverflow.com/questions/ 16655153/ и stackoverflow.com/questions/23146950/   -  person Andrew Henle    schedule 13.03.2019
comment
@AndrewHenle Хорошая идея. Он вернул -1, а errno в обоих случаях установлено на 78. Похоже, это означает, что функция не установлена. Интересно.   -  person TheStrangeQuark    schedule 13.03.2019
comment
@TheStrangeQuark При компиляции с помощью gcc или clang всегда следует использовать параметр -Wall.   -  person user3386109    schedule 13.03.2019
comment
К сведению, на моей машине (Debian GNU/Linux 9, GCC 6.3, Pthreads 2.24) он вернул 0, а errno установлено в 0 в обоих случаях. Также для сведения, компилирую с -Wall и, действительно, еще и с -Wextra -Werror.   -  person thb    schedule 13.03.2019
comment
Если вам действительно нужен мьютекс (а не счетный семафор), взгляните на pthread_mutex_create, pthread_mutex_lock и pthread_mutex_unlock.   -  person user3386109    schedule 13.03.2019
comment
Запуск этого в Linux работает нормально. @user3386109 прав, что они устарели, и я не должен их использовать. Всем спасибо   -  person TheStrangeQuark    schedule 13.03.2019


Ответы (1)


Я не знаю, почему ваш код не работает. К сожалению, для нашей нынешней цели ваш код успешно работает на моей машине.

Пока кто-то другой не опубликует правильный ответ, если вы хотите попробовать со мной несколько идей по отладке, по вашему выбору, мы можем попробовать следующее.

1. Попробуйте предложение @AndrewHenle: «Что возвращает sem_getvalue() в обоих случаях? Если он возвращает ненулевое значение, что такое errno

Для информации, на моей машине (Debian GNU/Linux 9, GCC 6.3, Pthreads 2.24) он возвращает ноль, и errno также равно нулю.

2. Попробуйте изменить

sem_t mutex;

to

volatile unsigned char buffer_before_mutex[0x1000];
sem_t mutex;
volatile unsigned char buffer_after_mutex[0x1000];

Причина: если что-то перезаписывает ваш мьютекс в стеке, это может дать ему пустое место для перезаписи вместо того, чтобы уничтожить мьютекс. Даже если это сработает (а я подозреваю, что не сработает), это будет неправильно; но это может дать ключ к пониманию того, что не так с вашим кодом.

3. (Возможно, мой ответ затерялся в комментариях. Я оставляю ответ здесь на случай, если часть его все же окажется полезной.)

person thb    schedule 13.03.2019
comment
Чего OP не заметил, так это того, что sem_init и sem_getvalue устарели в MacOS. Компиляция с -Wall сделала бы это предельно ясным. Функции — это просто заглушки, которые устанавливают errno и возвращаются. - person user3386109; 13.03.2019