c - C 中的命名共享内存问题

标签 c shared-memory memory-mapped-files

我正在编写一个程序,使用 5 个线程查找最大为 4294967295 (unsigned int) 的素数。每个线程使用 IsPrime() 函数获取一系列数字来检查(我从代码中删除了该函数,因为它不是代码中断的地方),如果数字是质数,它将把大小为 500 MB 的命名共享内存文件中的编号。为了确保程序正常运行,我从小范围的数字开始:0 到 25。因此每个线程获得 5 个数字来检查并将其放入映射文件中。这是代码:

#define _BSD_SOURCE

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

/* The program is using 5 threads to find prime numbers.
therefore, each thread is responsible for finding the numbers
with in a specific range: unsigned int / 5
*/

#define THREAD_1_BEGIN 0
#define THREAD_1_END 5

#define THREAD_2_BEGIN 6
#define THREAD_2_END 10

#define THREAD_3_BEGIN 11
#define THREAD_3_END 15

#define THREAD_4_BEGIN 16
#define THREAD_4_END 20

#define THREAD_5_BEGIN 21
#define THREAD_5_END 25



// The shared variable to hold the total number of primes.
unsigned int totalPrimes = 0;

// Shared memory variables
unsigned char *bitmap;
unsigned int bitmap_size = 4294967295 / 8 + 1; // size of unsigned int
unsigned int *prime_numbers;
unsigned int object_size = 1024 * 1024 * 500; // 500 MB
void *addr;

// Threads
pthread_t threads[5];
pthread_mutex_t total_Mutex;

void *ThreadWorker(void *threadId);
int IsPrime(unsigned int number);
void *mount_shmem(char *path, unsigned int object_size); 

int main(int argc, char **argv)
{
  int i;
  void *status;

  // Set the threads attributes and mutex
  pthread_attr_t attr;

  pthread_mutex_init(&total_Mutex, NULL);

  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

  // Set the shared memory
  addr = mount_shmem("threadedshm", object_size);
  bitmap = addr;

  prime_numbers = (unsigned int*)(bitmap + bitmap_size);

  for(i = 0; i<5; i++){
    pthread_create(&threads[i], &attr, ThreadWorker, (void *)i);
  }

  pthread_attr_destroy(&attr);

  // Wait for each thread
  for(i = 0; i<5; i++){
    pthread_join(threads[i], &status);
  }

  printf("\n TOTAL: %u \n", totalPrimes);

  pthread_mutex_destroy(&total_Mutex);
  pthread_exit(NULL);

}

void *ThreadWorker(void *threadId)
{
  int pos = (int) threadId;
  unsigned int t1;
  unsigned int t2;
  unsigned int t3;
  unsigned int t4;
  unsigned int t5;

  if(pos == 0){
    for(t1 = THREAD_1_BEGIN; t1 <= THREAD_1_END; t1++){
      if(IsPrime(t1)){
        printf("Thread 1: %u\n", t1);

        // put it in the shared memory file
        prime_numbers[totalPrimes] = t1;

        // Increment the counter by 1
        pthread_mutex_lock(&total_Mutex);
        totalPrimes++;
        pthread_mutex_unlock(&total_Mutex);
      }
    } 
  }else if(pos == 1){
    for(t2 = THREAD_2_BEGIN; t2 <= THREAD_2_END; t2++){
      if(IsPrime(t2)){
        printf("Thread 2: %u\n", t2);

        // put it in the shared memory file
        prime_numbers[totalPrimes] = t2;

        // Increment the counter by 1
        pthread_mutex_lock(&total_Mutex);
        totalPrimes++;
        pthread_mutex_unlock(&total_Mutex);
      }
    } 
  }else if(pos == 2){
    for(t3 = THREAD_3_BEGIN; t3 <= THREAD_3_END; t3++){
      if(IsPrime(t3)){
        printf("Thread 3: %u\n", t3);

        // put it in the shared memory file
        prime_numbers[totalPrimes] = t3;

        // Increment the counter by 1
        pthread_mutex_lock(&total_Mutex);
        totalPrimes++;
        pthread_mutex_unlock(&total_Mutex);
      }
    } 
  }else if(pos == 3){
    for(t4 = THREAD_4_BEGIN; t4 <= THREAD_4_END; t4++){
      if(IsPrime(t4)){
        printf("Thread 4: %u\n", t4);

        // put it in the shared memory file
        prime_numbers[totalPrimes] = t4;

        // Increment the counter by 1
        pthread_mutex_lock(&total_Mutex);
        totalPrimes++;
        pthread_mutex_unlock(&total_Mutex);
        printf("Thread 4: %u\n", t4);

        // put it in the shared memory file
        prime_numbers[totalPrimes] = t4;

        // Increment the counter by 1
        pthread_mutex_lock(&total_Mutex);
        totalPrimes++;
        pthread_mutex_unlock(&total_Mutex);
      }
    } 
  }else if(pos == 4){
    for(t5 = THREAD_5_BEGIN; t5 <= THREAD_5_END; t5++){
      if(IsPrime(t5)){
        printf("Thread 5: %u\n", t5);

        // put it in the shared memory file
        prime_numbers[totalPrimes] = t5;

        // Increment the counter by 1
        pthread_mutex_lock(&total_Mutex);
        totalPrimes++;
        pthread_mutex_unlock(&total_Mutex);
      }
    } 
  }

  pthread_exit((void*) 0);
}

void *mount_shmem(char *path, unsigned int object_size){
    int shmem_fd;
    void *addr;

    // create and resize the file
    shmem_fd = shm_open(path, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
    if (shmem_fd == -1){
        fprintf(stdout, "failed to open shared memory object\n");
        exit(EXIT_FAILURE);
    }
    // resize it to 500 MB
    if (ftruncate(shmem_fd, object_size) == -1){
        fprintf(stdout, "failed to resize shared memory object\n");
        exit(EXIT_FAILURE);     
    }

    addr = mmap(NULL, object_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmem_fd, 0);
    if (addr == MAP_FAILED){
        fprintf(stdout, "failed to map shared memory object\n");
        exit(EXIT_FAILURE);
    }

    return addr;
}

但是,在将数字插入数组时 (prime_numbers[totalPrimes] = t1;),我遇到了段错误。启动共享内存文件时,我无法弄清楚我做错了什么。我尝试只使用一个线程,因为我怀疑这可能是一个互斥问题,多个线程试图同时更新文件,但这不是问题(我知道我最终会需要互斥量或信号量)。任何帮助将不胜感激。

最佳答案

这一行:

prime_numbers = (unsigned int*)(bitmap + bitmap_size);

prime_numbers 设置为指向远远超出 bitmap 指向的共享内存区域的范围(这是导致崩溃的原因)。

你也有一个竞争条件,在这样的代码中:

    // put it in the shared memory file
    prime_numbers[totalPrimes] = t1;

    // Increment the counter by 1
    pthread_mutex_lock(&total_Mutex);
    totalPrimes++;
    pthread_mutex_unlock(&total_Mutex);

由于您在锁外读取 totalPrimes 以确定要写入的数组索引,因此两个线程可以写入同一个数组索引,从而导致更新丢失。您可以通过在执行增量时获取要写入的数组索引来解决此问题:

    // Increment the counter by 1
    pthread_mutex_lock(&total_Mutex);
    thisPrime = totalPrimes++;
    pthread_mutex_unlock(&total_Mutex);

    // put it in the shared memory file
    prime_numbers[thisPrime] = t1;

关于c - C 中的命名共享内存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13373154/

相关文章:

c++ - OpenFileMapping() 找不到在 COM DLL 中创建的 MMF

c - Unix 编程共享内存奇怪的结果

c++ - CreateSharedMemory 用法

c - 包括头文件

java - 如何在java中写出一个二维数组以便C程序可以读取它

c - 从内存中读取数据mmap

c++ - sqlite C\C++ 库是否将 DB 文件保存为内存映射文件?有可能让它这样做吗?

C++:创建大内存映射文件会卡住 pc

Python 函数胶囊

c++ - 优化:为什么 < 比 multiple 更昂贵!=