อะไรและทำไมของmutex แบบเรียกซ้ำไม่ควรเป็นสิ่งที่ซับซ้อนดังที่อธิบายไว้ในคำตอบที่ยอมรับ
ฉันอยากจะเขียนความเข้าใจของฉันหลังจากที่ขุดดูในเน็ต
อันดับแรกคุณควรตระหนักว่าเมื่อพูดถึงmutexแนวคิดแบบมัลติเธรดก็มีส่วนเกี่ยวข้องด้วยเช่นกัน (mutex ใช้สำหรับการซิงโครไนซ์ฉันไม่ต้องการ mutex ถ้าฉันมีเพียง 1 เธรดในโปรแกรมของฉัน)
ประการที่สองคุณควรทราบความแตกต่าง bewteen ที่mutex ปกติและmutex recursive
อ้างจากAPUE :
(mutex แบบเรียกซ้ำคือ a) ประเภท mutex ที่อนุญาตให้เธรดเดียวกันล็อกได้หลายครั้งโดยไม่ต้องปลดล็อกก่อน
ความแตกต่างที่สำคัญคือภายในเธรดเดียวกันการล็อกซ้ำการล็อกซ้ำไม่ทำให้เกิดการชะงักงันและไม่ปิดกั้นเธรด
นี่หมายความว่าการล็อกแบบหักล้างไม่เคยทำให้เกิดการชะงักงันหรือไม่?
ไม่มันยังสามารถทำให้เกิดการหยุดชะงักได้เหมือน mutex ปกติหากคุณล็อกไว้ในเธรดเดียวโดยไม่ได้ปลดล็อกและพยายามล็อกไว้ในเธรดอื่น
มาดูโค้ดกันเป็นหลักฐาน
- mutex ปกติพร้อมการหยุดชะงัก
#include <pthread.h>
#include <stdio.h>
pthread_mutex_t lock;
void * func1(void *arg){
printf("thread1\n");
pthread_mutex_lock(&lock);
printf("thread1 hey hey\n");
}
void * func2(void *arg){
printf("thread2\n");
pthread_mutex_lock(&lock);
printf("thread2 hey hey\n");
}
int main(){
pthread_mutexattr_t lock_attr;
int error;
error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_DEFAULT);
if(error){
perror(NULL);
}
pthread_mutex_init(&lock, &lock_attr);
pthread_t t1, t2;
pthread_create(&t1, NULL, func1, NULL);
pthread_create(&t2, NULL, func2, NULL);
pthread_join(t2, NULL);
}
เอาต์พุต:
thread1
thread1 hey hey
thread2
ตัวอย่างการหยุดชะงักทั่วไปไม่มีปัญหา
- mutex แบบเรียกซ้ำพร้อมการหยุดชะงัก
เพียงแค่ยกเลิกการ
error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
แสดงความคิดเห็นในบรรทัดนี้และแสดงความคิดเห็นอีกบรรทัด
เอาต์พุต:
thread1
thread1 hey hey
thread2
ใช่ mutex แบบเรียกซ้ำอาจทำให้เกิดการหยุดชะงักได้เช่นกัน
- mutex ปกติล็อคในเธรดเดียวกัน
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
pthread_mutex_t lock;
void func3(){
printf("func3\n");
pthread_mutex_lock(&lock);
printf("func3 hey hey\n");
}
void * func1(void *arg){
printf("thread1\n");
pthread_mutex_lock(&lock);
func3();
printf("thread1 hey hey\n");
}
void * func2(void *arg){
printf("thread2\n");
pthread_mutex_lock(&lock);
printf("thread2 hey hey\n");
}
int main(){
pthread_mutexattr_t lock_attr;
int error;
error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_DEFAULT);
if(error){
perror(NULL);
}
pthread_mutex_init(&lock, &lock_attr);
pthread_t t1, t2;
pthread_create(&t1, NULL, func1, NULL);
sleep(2);
pthread_create(&t2, NULL, func2, NULL);
pthread_join(t2, NULL);
}
เอาต์พุต:
thread1
func3
thread2
การหยุดชะงักในthread t1
, ในfunc3
.
(ฉันใช้sleep(2)
เพื่อให้ง่ายขึ้นเพื่อดูว่าการชะงักงันเกิดจากการล็อคใหม่func3
)
- mutex แบบเรียกซ้ำล็อคซ้ำในเธรดเดียวกัน
อีกครั้งยกเลิกการใส่ข้อคิดเห็นบรรทัด mutex แบบเรียกซ้ำและแสดงความคิดเห็นในบรรทัดอื่น
เอาต์พุต:
thread1
func3
func3 hey hey
thread1 hey hey
thread2
การหยุดชะงักในthread t2
, ในfunc2
. ดู? func3
เสร็จสิ้นและออกการล็อคใหม่ไม่ได้ปิดกั้นเธรดหรือนำไปสู่การหยุดชะงัก
คำถามสุดท้ายทำไมเราถึงต้องการ?
สำหรับฟังก์ชันเรียกซ้ำ (เรียกในโปรแกรมมัลติเธรดและคุณต้องการปกป้องทรัพยากร / ข้อมูลบางส่วน)
เช่นคุณมีโปรแกรมมัลติเธรดและเรียกใช้ฟังก์ชันวนซ้ำในเธรด A คุณมีข้อมูลบางอย่างที่ต้องการป้องกันในฟังก์ชันเรียกซ้ำนั้นดังนั้นคุณจึงใช้กลไก mutex การดำเนินการของฟังก์ชันนั้นเป็นลำดับในเธรด A ดังนั้นคุณจะต้องล็อก mutex ซ้ำในการเรียกซ้ำ ใช้ mutex ปกติทำให้เกิดการชะงักงัน และมีการคิดค้นmutexเพื่อแก้ปัญหานี้
ดูตัวอย่างจากคำตอบที่ยอมรับ
เมื่อใดควรใช้การเรียกซ้ำ mutex .
Wikipedia อธิบาย mutex แบบเรียกซ้ำได้เป็นอย่างดี คุ้มค่าสำหรับการอ่าน Wikipedia: Reentrant_mutex