尝试锁定共享内存互斥体时出现分段错误

Posted

技术标签:

【中文标题】尝试锁定共享内存互斥体时出现分段错误【英文标题】:Segmentation Fault when trying to lock a shared memory mutex 【发布时间】:2019-01-22 17:41:34 【问题描述】:

共享内存互斥体的分段错误。我分别有一个生产者和一个消费者进程,生产者初始化共享内存,共享内存互斥体,并写入数据。

消费者打开共享内存,尝试锁定和读取数据。

没有互斥体,消费者可以读取数据(数据会不一致,但没有seg错误)

只有当消费者试图锁定互斥体时才会出现段错误。

更改了flags,结果还是一样,检查了attr和mutex init的返回值,都很好。

我有点迷茫,而且我对共享内存还很陌生。

指出的任何缺陷都会非常有帮助。谢谢!

堆栈:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff79c0c8d in pthread_mutex_lock () from /lib64/libpthread.so.0
(gdb) bt
#0  0x00007ffff79c0c8d in pthread_mutex_lock () from /lib64/libpthread.so.0
#1  0x00000000004008ec in main (argc=1, argv=0x7fffffffde18 "\210\341\377\377\377\177") at cons.c:41
(gdb) p cons_ptr
$1 = (test_str_t *) 0x7ffff7ff7000
(gdb) p cons_ptr->data[0] 
$2 = 873422052  
(gdb) p cons_ptr->magic 
$3 = 43981  
(gdb) p cons_ptr->shm_lock
$4 = __data = __lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 128, __spins = 0, __elision = 0, __list = __prev = 0x0, __next = 0x0, 
  __size = '\000' <repeats 16 times>, "\200", '\000' <repeats 22 times>, __align = 0
(gdb) 


// Header:  

const char *pathname = "test_shm";

typedef struct test_str_
    uint64_t            magic;
    int                 data[1024];
    pthread_mutex_t     shm_lock;
    uint64_t            magic2;
test_str_t;

// Producer:  

#include "test_header.h"
#include <time.h>

test_str_t *ptr;

void init_mutex(pthread_mutex_t *mutex)
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
    pthread_mutex_init(mutex, &attr);
    pthread_mutexattr_destroy(&attr);


int main(int argc, char *argv[]) 
    int fd, i = 0, num_int = 1024, rc = 0;
    int size = num_int * sizeof(int);
    fd = shm_open(pathname, O_CREAT|O_RDWR, 0666);
    if(fd == -1) 
        printf("\n shm_open failed \n");
        exit(0);
    
    rc = ftruncate(fd, sizeof(test_str_t));
    ptr = (test_str_t *)mmap(NULL, sizeof(test_str_t),
                    PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
    if(ptr == MAP_FAILED) 
        printf("\n mmap failed \n");
        exit(0);
    
    rc = init_mutex(&(ptr->shm_lock));
    if(rc != 0) 
        printf("Mutex Init failed: rc:[%d]\n", rc);
        exit(0);
    
    ptr->magic = 0xABCD;
    ptr->magic2 = 0xEF12;
    srand(time(0));
    for(i = 0; i < 5; i++) 
        pthread_mutex_lock(&(ptr->shm_lock));
        ptr->data[i] = i;
        pthread_mutex_unlock(&(ptr->shm_lock));
    
    return 0;


// Consumer:  

#include "test_header.h"
#include <time.h>

test_str_t *cons_ptr;

int main(int argc, char *argv[]) 
    int fd, i = 0, num_int = 1024, rc = 0;
    int try_lock = 0;
    int size = num_int * sizeof(int);
    fd = shm_open(pathname, O_RDONLY, 0666);
    if(fd == -1) 
        printf("\n shm_open failed \n");
        exit(0);
    
    cons_ptr = (test_str_t *)mmap(NULL, sizeof(test_str_t),
                    PROT_READ, MAP_SHARED, fd, 0);
    if(cons_ptr == MAP_FAILED) 
        printf("\n mmap failed \n");
        exit(0);
    
    if(cons_ptr == NULL) 
        printf("\n NULL Ptr\n");
        return 0;
    
    printf("Magic: [0x%x] [0x%x]\n", cons_ptr->magic, cons_ptr->magic2);
    //int try_lock = pthread_mutex_lock(&(cons_ptr->shm_lock)); // SEG FAULT
    for(i = 0; i < 5; i++) 
        printf("\nNumber:[%d]\n", cons_ptr->data[i]);
        sleep(1);
    
    //pthread_mutex_unlock(&(cons_ptr->shm_lock)); // SEG FAULT
    return 0;

【问题讨论】:

首先检查堆栈跟踪是否存在段错误。 所有pthread_*() 函数返回什么?您应该首先确保它们正常工作。 @Andrew Henle 我确实检查了返回值,它们都返回 0。它们很好。当我尝试锁定生​​产者进程时,返回值为 0。 @SergeyA - 我已经添加了跟踪,看起来不错。 @Gerhardh - 你能告诉我缺少哪些信息吗? 【参考方案1】:

(1) 这里有一个问题: ptr->data = rand(); data 是一个 int*,并且您已将该指针替换为随机地址。您在几个地方执行此操作,我没有看到确切发生了什么,但这是我现在看到的最明显的错误。

(2) 我看到的下一件事是,在消费者中,您以只读方式打开文件并将内存映射为只读,但 pthread_mutex_lock 和 pthread_mutex_unlock 需要能够修改互斥锁,因此这可能会导致一些麻烦。

【讨论】:

谢谢,我将 data[i] 更改为指向 i 本身的值,遗憾的是我仍然遇到相同的 SEG 错误。但消费者仍然能够检索 i 的值,从 0 到 4。 是的!这就是诀窍,将其设置为在消费者进程上写入权限使其工作!谢谢! :) 我花了一秒钟才注意到它,因为我不相信我曾经使用过这种共享内存机制。令人惊讶的是,因为它看起来非常简单和有用......如果你身体状况良好,你应该接受我认为的答案。不客气。

以上是关于尝试锁定共享内存互斥体时出现分段错误的主要内容,如果未能解决你的问题,请参考以下文章

访问共享进程内存时出现分段错误(核心转储)

使用共享内存时出现分段错误

一个用户崩溃时共享内存中的互斥锁?

共享内存锁定和进程崩溃

尝试从 docker 容器访问共享内存时出现“权限被拒绝”,即使 --ipc 设置为“主机”

通过共享内存和管道的 IPC 给出分段错误:C 中的 11