ค่าสัญญาณในฟังก์ชันภายในฟังก์ชันเธรดไม่สอดคล้องกัน

ฉันได้เรียนรู้วิธีใช้ pthreads และ mutexes แล้ว และฉันสับสนเกี่ยวกับผลลัพธ์ของโค้ด 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

เหตุใดค่า mutex จึงเปลี่ยนแปลงในฟังก์ชันที่ฉันเรียกภายในเธรด ฉันสูญเสียการอ้างอิงถึง mutex หรือไม่?


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
หากคุณต้องการ mutex จริงๆ (ไม่ใช่เซมาฟอร์นับ) ลองดูที่ 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];

เหตุผล: หากมีบางสิ่งเขียนทับ mutex ของคุณบนสแต็ก นี่อาจทำให้มีพื้นที่ว่างในการเขียนทับแทนที่จะทิ้ง mutex แม้ว่าวิธีนี้จะได้ผล (และฉันสงสัยว่าจะไม่เป็นเช่นนั้น) มันก็จะไม่ถูกต้อง แต่อาจเป็นเบาะแสว่าเกิดอะไรขึ้นกับโค้ดของคุณ

3. (คำตอบของฉันอาจถูกครอบงำโดยความคิดเห็น ฉันทิ้งคำตอบไว้ที่นี่เผื่อว่าส่วนหนึ่งจะมีประโยชน์)

person thb    schedule 13.03.2019
comment
สิ่งที่ OP ไม่สังเกตเห็นก็คือ sem_init และ sem_getvalue เลิกใช้แล้วบน MacOS การคอมไพล์ด้วย -Wall จะทำให้ชัดเจนมาก ฟังก์ชั่นเป็นเพียงโครงที่ตั้งค่า errno และส่งคืน - person user3386109; 13.03.2019