有强大的互斥量的bug

Yev*_*y P 8 c++ linux mutex ipc pthreads

我试图在linux上使用强大的互斥锁来保护进程之间的资源,而在某些情况下,它们似乎不会以"健壮"的方式运行.通过"健壮"的方式,我的意思是如果拥有锁的进程已经终止,pthread_mutex_lock应该返回EOWNERDEAD.

这是不起作用的场景:

2个过程p1和p2.p1创建健壮的互斥锁并等待它(在用户输入之后).p2有2个线程:线程1映射到互斥锁并获取它.线程2(在线程1获取互斥锁之后)也映射到相同的互斥锁并等待它(因为线程1现在拥有它).另请注意,在p2-thread1已经获取后,p1开始在互斥锁上等待.

现在,如果我们终止p2,p1永远不会解锁(意味着它的pthread_mutex_lock永远不会返回),这与假定的"健壮性"相反,其中p1应该用EOWNERDEAD错误解除阻塞.

这是代码:

p1.cpp:

    #include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

struct MyMtx {
    pthread_mutex_t m;
};

int main(int argc, char **argv)
{
    int r;

    pthread_mutexattr_t ma;
    pthread_mutexattr_init(&ma);
    pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED);
    pthread_mutexattr_setrobust_np(&ma, PTHREAD_MUTEX_ROBUST_NP);

    int fd = shm_open("/test_mtx_p", O_RDWR|O_CREAT, 0666);
    ftruncate(fd, sizeof(MyMtx));

    MyMtx *m = (MyMtx *)mmap(NULL, sizeof(MyMtx),
        PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
    //close (fd);

    pthread_mutex_init(&m->m, &ma);

    puts("Press Enter to lock mutex");
    fgetc(stdin);

    puts("locking...");
    r = pthread_mutex_lock(&m->m);
    printf("pthread_mutex_lock returned %d\n", r);

    puts("Press Enter to unlock");
    fgetc(stdin);
    r = pthread_mutex_unlock(&m->m);
    printf("pthread_mutex_unlock returned %d\n", r);

    puts("Before pthread_mutex_destroy");
    r = pthread_mutex_destroy(&m->m);
    printf("After pthread_mutex_destroy, r=%d\n", r);

    munmap(m, sizeof(MyMtx));
    shm_unlink("/test_mtx_p");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

p2.cpp:

    #include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

struct MyMtx {
    pthread_mutex_t m;
};

static void *threadFunc(void *arg)
{
    int fd = shm_open("/test_mtx_p", O_RDWR|O_CREAT, 0666);
    ftruncate(fd, sizeof(MyMtx));

    MyMtx *m = (MyMtx *)mmap(NULL, sizeof(MyMtx),
        PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
    sleep(2); //to let the first thread lock the mutex
    puts("Locking from another thread");
    int r = 0;
    r = pthread_mutex_lock(&m->m);
    printf("locked from another thread r=%d\n", r);
}

int main(int argc, char **argv)
{
    int r;
    int fd = shm_open("/test_mtx_p", O_RDWR|O_CREAT, 0666);
    ftruncate(fd, sizeof(MyMtx));

    MyMtx *m = (MyMtx *)mmap(NULL, sizeof(MyMtx),
        PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
    //close (fd);

    pthread_t tid;
    pthread_create(&tid, NULL, threadFunc, NULL);

    puts("locking");
    r = pthread_mutex_lock(&m->m);
    printf("pthread_mutex_lock returned %d\n", r);

    puts("Press Enter to terminate");
    fgetc(stdin);

    kill(getpid(), 9);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

首先,运行p1,然后运行p2并等待它打印"从另一个线程锁定".在p1的shell上按Enter键锁定互斥锁,然后在p2的shell上按Enter键终止p2,或者你可以用其它方式杀掉它.您将看到p1打印"锁定..."并且pthread_mutex_lock永远不会返回.

问题实际上并不是一直发生,看起来它取决于时机.如果你在p1开始锁定之后和终止p2之前经过一段时间,那么有时它会工作并且p2的pthread_mutex_lock返回130(EOWNERDEAD).但是如果在p1开始等待互斥锁之后或之后的短时间内终止p2,p1将永远不会解除阻塞.

还有其他人遇到过同样的问题吗?

moe*_*ake 0

尝试简化你的问题。看来你的问题是运行顺序。
始终考虑最坏的情况:即使你运行 A 然后 B,B 仍然可以完成,而 A 刚刚开始运行。如有必要,请添加互斥控制。
这是 A(生产者)和 B(消费者)的简单示例:

        Main:
            Call A

        A:
            Lock
            Call B
            Produce
            Unlock

        B:
            Lock
            Consume
            Unlock
Run Code Online (Sandbox Code Playgroud)