Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 具有健壮互斥的Bug_C++_Linux_Pthreads_Ipc_Mutex - Fatal编程技术网

C++ 具有健壮互斥的Bug

C++ 具有健壮互斥的Bug,c++,linux,pthreads,ipc,mutex,C++,Linux,Pthreads,Ipc,Mutex,我试图在linux上使用健壮的互斥体来保护进程之间的资源,在某些情况下,它们的行为似乎并不“健壮”。通过“健壮”的方式,我的意思是,如果拥有锁的进程已经终止,pthread_mutex_lock应该返回eownerded 以下是它不起作用的场景: 2处理p1和p2。p1创建健壮的互斥体并等待它(在用户输入之后)。p2有2个线程:线程1映射到互斥体并获取它。线程2(在线程1获得互斥锁后)也映射到同一互斥锁并等待它(因为线程1现在拥有它)。还请注意,p1在p2-thread1已经获取互斥锁后开始等待

我试图在linux上使用健壮的互斥体来保护进程之间的资源,在某些情况下,它们的行为似乎并不“健壮”。通过“健壮”的方式,我的意思是,如果拥有锁的进程已经终止,pthread_mutex_lock应该返回eownerded

以下是它不起作用的场景:

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

现在,如果我们终止p2,p1永远不会解除阻塞(意味着它的pthread\u mutex\u lock永远不会返回),这与假定的“健壮性”相反,在这里p1应该使用eownerded错误解除阻塞

代码如下:

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;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
结构MyMtx{
pthread_mutex_t m;
};
int main(int argc,字符**argv)
{
INTR;
pthread_mutexttr_ma;
pthread_mutexattr_init(&ma);
pthread_mutexattr_setpshared(&ma,pthread_PROCESS_SHARED);
pthread_mutextatr_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),
保护读写,映射共享,fd,0);
//关闭(fd);
pthread_mutex_init(&m->m,&ma);
puts(“按Enter键锁定互斥锁”);
fgetc(stdin);
放置(“锁定…”);
r=pthread\u mutex\u lock(&m->m);
printf(“pthread\u mutex\u lock返回%d\n”,r);
puts(“按回车键解锁”);
fgetc(stdin);
r=pthread\u mutex\u unlock(&m->m);
printf(“pthread\u mutex\u unlock返回%d\n”,r);
puts(“在pthread_mutex_destroy之前”);
r=pthread\u mutex\u destroy(&m->m);
printf(“在pthread\u mutex\u destroy之后,r=%d\n”,r);
munmap(m,sizeof(MyMtx));
shm_解除链接(“/test_mtx_p”);
返回0;
}
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;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
结构MyMtx{
pthread_mutex_t m;
};
静态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),
保护读写,映射共享,fd,0);
sleep(2);//让第一个线程锁定互斥锁
puts(“从另一个线程锁定”);
int r=0;
r=pthread\u mutex\u lock(&m->m);
printf(“从另一个线程锁定r=%d\n”,r);
}
int main(int argc,字符**argv)
{
INTR;
int fd=shm_open(“/test_mtx_p”,O_RDWR | O_CREAT,0666);
ftruncate(fd,sizeof(MyMtx));
MyMtx*m=(MyMtx*)mmap(NULL,sizeof(MyMtx),
保护读写,映射共享,fd,0);
//关闭(fd);
pthread_t tid;
pthread_create(&tid,NULL,threadFunc,NULL);
看跌期权(“锁定”);
r=pthread\u mutex\u lock(&m->m);
printf(“pthread\u mutex\u lock返回%d\n”,r);
卖出(“按回车键终止”);
fgetc(stdin);
kill(getpid(),9);
返回0;
}
首先,运行p1,然后运行p2并等待它打印“来自另一个线程的锁定”。在p1的外壳上按Enter键锁定互斥锁,然后在p2的外壳上按Enter键终止p2,或者您可以通过其他方式终止它。您将看到p1打印“锁定…”,pthread_mutex_lock永远不会返回

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


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

尽量简化您的问题。您的问题似乎是运行序列。
总是考虑最坏的情况:即使你运行一个B,B仍然可以完成,而刚刚开始运行。如有必要,添加互斥控制。
以下是a(生产者)和B(消费者)的简单示例:


刚刚在Linux内核2.6.32及更新版本上验证了glibc版本2.11.1的行为

我的第一个发现是:如果在p2中的“从另一个线程锁定”之前在p1中按Enter键(在2s内),那么健壮的互斥锁可以正常工作。正如人们所料。结论:等待线程的顺序很重要

第一个等待的线程被唤醒。不幸的是,p2中的线程在当时被杀死

有关问题的说明,请参阅

我不知道周围是否有内核补丁。甚至不知道它是否被认为是一个bug

尽管如此,似乎还是有解决整个混乱局面的办法。将健壮的互斥体与PTHREAD_PRIO_INHERIT一起使用:

pthread_mutexattr_setprotocol(&ma, PTHREAD_PRIO_INHERIT);

在内核内部(futex.c)而不是handle_futex_death(),exit_pi_state_list()中的其他机制会处理其他互斥对象等待程序的唤醒。这似乎解决了问题

由于您两次获得锁(除非您使用的是可重入锁),您不会有死锁吗?不过,在我的示例中,我知道何时以及由谁从printfs获取锁。在任何情况下,进程2中的哪个线程将获得锁都无关紧要,根据我所理解的“健壮性”,当进程2死亡时,进程1应该能够获得锁。因此,也许您需要的是,在使用互斥时,您将需要它。如果您需要示例,我可以发布一个简单的示例。我不确定pthread_cond在这里有什么帮助,因为进程2已终止,因此它没有机会发出条件信号。我还更改了p2.cpp的代码,以避免两次映射到共享内存,方法是将MyMtx*m设为全局变量,并让threadFunc使用它而不是调用mmap。我得到了同样的结果。奇怪的是,当我用SIGTERM代替你的SIGKILL时,它出现了
pthread_mutexattr_setprotocol(&ma, PTHREAD_PRIO_INHERIT);