简体   繁体   中英

Access a memory mapped file's buffer from different threads

I want to divide the handling of some file data over multiple threads. I'm mapping the whole file in the main thread and then creating multiple threads that will handle the data from the mmapped buffer at different offsets.

However, even when just one thread is created my application is crashing: SIGSEGV, Segmentation fault.

As you can see just after mapping the file, I'm dumping the first 100 bytes from the mapped buffer which is OK.

But if I try to dump the first 100 bytes from the same mapped buffer, I'm getting the SIGSEV

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>

const unsigned NUM_THREADS = 1;
char *bufferBase = NULL;
char *bufferEnd = NULL;

struct thread_info
{
    pthread_t thread_id;
    int thread_num;
    size_t offset;
    size_t numSamples;
};

static void *thread_start(void *arg)
{
    struct thread_info *tinfo = (struct thread_info *)arg;
    printf("\nStart Thread %d\n", tinfo->thread_num);
    // Crashing when trying to Dump data here !!!
    printf("Dump mmap from thread\n");
    for (size_t i = 0; i < 100; i++)
    {
        printf("%x ", bufferBase[i]);
    }
    return NULL;
}

int main(int argc, char *argv[])
{
    int s = 0;
    if (argc < 2)
    {
        printf("Args error\n");
    }
    int file = open(argv[1], O_RDWR);
    if (file < 0)
    {
        printf("open failed\n");
        return false;
    }
    struct stat filestat;
    if (stat(argv[1], &filestat) != 0)
    {
        printf("stat failed\n");
        return false;
    }
    char *bufferBase = (char *)mmap(NULL, filestat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, file, 0);
    if (bufferBase == MAP_FAILED)
    {
        printf("mmap failed\n");
        return false;
    }
    // OK to Dump data here !!!
    printf("dump mmap\n");
    for (size_t i = 0; i < 100; i++)
    {
        printf("%x ", bufferBase[i]);
    }

    /* Initialize thread creation attributes */
    pthread_attr_t attr;

    s = pthread_attr_init(&attr);
    if (s != 0)
    {
        printf("pthread_attr_init failed\n");
        return false;
    }

    struct thread_info *tinfo = (struct thread_info *)calloc(NUM_THREADS, sizeof(struct thread_info));
    for (size_t i = 0; i < NUM_THREADS; i++)
    {
        tinfo[i].thread_num = i + 1;
        int s = pthread_create(&tinfo[i].thread_id, &attr,
                               &thread_start, &tinfo[i]);
        if (s != 0)
        {
            printf("pthread_create failed [%zu]\n", i);
            return false;
        }
    }

    void *res = NULL;
    for (size_t i = 0; i < NUM_THREADS; i++)
    {
        s = pthread_join(tinfo[i].thread_id, &res);
        if (s != 0)
        {
            printf("pthread_join failed [%zu]\n", i);
            return false;
        }
        printf("Joined with thread %d; returned value was %s\n",
               tinfo[i].thread_num, (char *)res);
    }
    return 0;
}

You are not modifying the global bufferBase but a local one.

 char *bufferBase = (char *)mmap(NULL, filestat.st_size, ...

Remove char * in the above line in main .

You declare a local variable bufferBase in main() whch hides (shadows) the global variable, so the function accesses via a null pointer.

Change:

char *bufferBase = (char *)mmap(NULL, filestat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, file, 0);

to:

bufferBase = (char *)mmap(NULL, filestat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, file, 0);

Compile with -Wshadow if using GCC or Clang to have the compiler warn you when you're making this mistake.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM