【发布时间】:2021-05-24 04:48:19
【问题描述】:
当我在前一个所有者已死的情况下尝试使用“trylock”锁定互斥锁时,我发现了意外行为
无需解锁。
使用“trylock”的第一个进程按预期获得 EOWNERDEAD 状态,因此使用“解锁”函数释放互斥锁:
lock_status = pthread_mutex_trylock(mutex);
if (lock_status == EOWNERDEAD)
{
pthread_mutex_unlock(mutex);
printf("P1 mutex status: EOWNERDEAD\n");
}
else if (lock_status == ENOTRECOVERABLE)
{printf("P1 mutex status: ENOTRECOVERABLE\n");}
else if (lock_status == EBUSY)
{printf("P1 mutex status: EBUSY\n");}
else {printf("P1 mutex status: %d\n", lock_status);}
第二个执行相同的代码,获得 ENOTRECOVERABLE 状态,正如预期的那样。
但是当第三个执行相同的操作时,会进入 EBUSY 状态,这是出乎意料的。
状态应该是 ENOTRECOVERABLE 报告的here
我尝试使用 'lock' 功能而不是 'trylock' 并返回正确的状态。
那是一个错误吗?在我的目的中,我必须在执行任何操作之前检查互斥锁状态,所以我不能使用“锁定”功能,否则可能会发生死锁。
我正在考虑在 ENOTRECOVERABLE 状态返回时销毁互斥锁:
else if (lock_status == ENOTRECOVERABLE)
{
pthread_mutex_destroy(mutex);
printf("P1 mutex status: ENOTRECOVERABLE\n");
}
但也许有比这种激烈的解决方案更好的方法,不是吗? 完整代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
main(void)
{
int lock_status, mutex_fdesc;
pid_t process_id;
pthread_mutex_t* mutex;
pthread_mutexattr_t m_att;
//Process 1 die with locked mutex
process_id = fork();
if (process_id < 0) {exit(0);}
if (process_id == 0)
{
usleep(100000);
mutex_fdesc = shm_open("/mutex", O_RDWR, S_IRWXU | S_IRWXG);
mutex = (pthread_mutex_t*)mmap(NULL, sizeof(pthread_mutex_t),
PROT_READ | PROT_WRITE, MAP_SHARED, mutex_fdesc, 0);
close(mutex_fdesc);
pthread_mutex_lock(mutex);
exit(0);
}
///Process 2 try to lock mutex and gets EOWNERDEAD then make an unlock
process_id = fork();
if (process_id < 0) {exit(0);}
if (process_id == 0)
{
usleep(200000);
mutex_fdesc = shm_open("/mutex", O_RDWR, S_IRWXU | S_IRWXG);
mutex = (pthread_mutex_t*)mmap(NULL, sizeof(pthread_mutex_t),
PROT_READ | PROT_WRITE, MAP_SHARED, mutex_fdesc, 0);
close(mutex_fdesc);
lock_status = pthread_mutex_trylock(mutex);
if (lock_status == EOWNERDEAD)
{
pthread_mutex_unlock(mutex);
printf("P2 mutex status: EOWNERDEAD\n");}
else if (lock_status == ENOTRECOVERABLE)
{printf("P2 mutex status: ENOTRECOVERABLE\n");}
else if (lock_status == EBUSY)
{printf("P2 mutex status: EBUSY\n");}
else {printf("P2 mutex status: %d\n", lock_status);}
exit(0);
}
///Process 2 try to lock mutex and gets ENOTRECOVERABLE then do nothing
process_id = fork();
if (process_id < 0) {exit(0);}
if (process_id == 0)
{
usleep(400000);
mutex_fdesc = shm_open("/mutex", O_RDWR, S_IRWXU | S_IRWXG);
mutex = (pthread_mutex_t*)mmap(NULL, sizeof(pthread_mutex_t),
PROT_READ | PROT_WRITE, MAP_SHARED, mutex_fdesc, 0);
close(mutex_fdesc);
lock_status = pthread_mutex_trylock(mutex);
if (lock_status == EOWNERDEAD)
{
pthread_mutex_unlock(mutex);
printf("P3 mutex status: EOWNERDEAD\n");}
else if (lock_status == ENOTRECOVERABLE)
{printf("P3 mutex status: ENOTRECOVERABLE\n");}
else if (lock_status == EBUSY)
{printf("P3 mutex status: EBUSY\n");}
else {printf("P3 mutex status: %d\n", lock_status);}
exit(0);
}
mutex_fdesc = shm_open("/mutex", O_RDWR | O_CREAT | O_EXCL, S_IRWXU | S_IRWXG);
ftruncate(mutex_fdesc, sizeof(pthread_mutex_t));
mutex = (pthread_mutex_t*)mmap(NULL, sizeof(pthread_mutex_t),
PROT_READ | PROT_WRITE, MAP_SHARED, mutex_fdesc, 0);
close(mutex_fdesc);
pthread_mutexattr_init(&m_att);
pthread_mutexattr_setpshared(&m_att, PTHREAD_PROCESS_SHARED);
pthread_mutexattr_setrobust(&m_att, PTHREAD_MUTEX_ROBUST);
pthread_mutex_init(mutex, &m_att);
pthread_mutexattr_destroy(&m_att);
///Parent process try to lock the mutex and gets EBUSY
usleep(800000);
lock_status = pthread_mutex_trylock(mutex);
if (lock_status == EOWNERDEAD)
{printf("Pparent mutex status: EOWNERDEAD\n");}
else if (lock_status == ENOTRECOVERABLE)
{printf("Pparent mutex status: ENOTRECOVERABLE\n");}
else if (lock_status == EBUSY)
{printf("Pparent mutex status: EBUSY\n");}
else {printf("Pparent mutex status: %d\n", lock_status);}
pthread_mutex_destroy(mutex);
munmap((void*)mutex, sizeof(pthread_mutex_t));
shm_unlink("/mutex");
wait(NULL);
wait(NULL);
wait(NULL);
exit(0);
}
【问题讨论】:
-
为什么不将原始所有者死亡的信息存储在您可以明确检查的正常状态下,并使用
pthread_mutex_consistent修复互斥锁? -
我认为这是唯一的方法,因为在返回 ENOTRECOVERABLE 状态后我不能原子地销毁互斥锁,并且其他线程可以使用“trylock”获取 EBUSY 状态。尽管如此,我认为这是一个错误。我在哪里可以举报?