将信号量与 POSIX 共享内存一起使用时出现分段错误
Segmentation fault when using semaphores with POSIX shared memory
我编写的一些简单代码有问题,这些代码是为了自学信号量和 POSIX 共享内存。
这个想法是一个程序,服务器,打开共享内存并向其中写入一个结构(包含一个信号量和一个数组)。然后它等待输入并在输入后增加信号量。
同时客户端打开共享内存,等待信号量,待服务器自增后,读取结构
服务器似乎工作正常,但是我在客户端的 sem_wait
函数中立即遇到段错误(甚至在服务器递增它之前)。我不知道哪里出了问题。
服务器代码:
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <semaphore.h>
#include <stdbool.h>
#define ARRAY_MAX 1024
typedef struct {
sem_t inDataReady;
float array[ARRAY_MAX];
unsigned arrayLen;
} OsInputData;
int main() {
int shm_fd;
OsInputData *shm_ptr;
if((shm_fd = shm_open("/my_shm", O_CREAT | O_RDWR, 0666)) == -1) {
printf("shm_open failure\n");
return 1;
}
if(ftruncate(shm_fd, sizeof(OsInputData)) == -1) {
printf("ftruncate failure\n");
return 1;
}
if((shm_ptr = (OsInputData*)mmap(0, sizeof(OsInputData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
printf("mmap failure\n");
return 1;
}
sem_init(&(shm_ptr->inDataReady), true, 0);
shm_ptr->array[0] = 3.0;
shm_ptr->array[1] = 1.0;
shm_ptr->array[2] = 2.0;
shm_ptr->array[3] = 5.0;
shm_ptr->array[4] = 4.0;
shm_ptr->arrayLen = 5;
getchar();
sem_post(&(shm_ptr->inDataReady));
sem_destroy(&(shm_ptr->inDataReady));
munmap(shm_ptr, sizeof(OsInputData));
close(shm_fd);
return 0;
}
客户代码:
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <semaphore.h>
#include <stdbool.h>
#define ARRAY_MAX 1024
typedef struct {
sem_t inDataReady;
float array[ARRAY_MAX];
unsigned arrayLen;
} OsInputData;
int main() {
int shm_fd;
OsInputData *shm_ptr;
if((shm_fd = shm_open("/my_shm", O_RDONLY, 0666)) == -1) {
printf("shm_open failure\n");
return 1;
}
if((shm_ptr = (OsInputData*)mmap(0, sizeof(OsInputData), PROT_READ, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
printf("mmap failure\n");
return 1;
}
sem_wait(&(shm_ptr->inDataReady));
printf("%u\n", shm_ptr->arrayLen);
munmap(shm_ptr, sizeof(OsInputData));
close(shm_fd);
return 0;
}
实际结果取决于您的系统,但通常您的程序包含错误。你不能破坏另一个 process/thread 可以到达的信号量。仅仅因为你执行了 sem_post 并不意味着你的系统已经切换到等待它的进程。当你毁掉它的时候,另一个人可能还在使用它。
SIGSEGV,在这种情况下,是一种善意。很少有程序员会检查 sem_wait 的 return 值,这可能导致程序认为它们是同步的,而实际上它们不是。
原来我必须在客户端中打开共享内存,同时具有读写权限,并相应地更新 mmap
中的保护。
相当愚蠢的错误,因为很明显客户端也需要写权限才能实际修改信号量。
因此在客户端代码中进行以下更改解决了它
...
shm_fd = shm_open("/my_shm", O_CREAT | O_RDWR, 0755)
...
shm_ptr = (OsInputData*)mmap(0, sizeof(OsInputData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0)
...
我编写的一些简单代码有问题,这些代码是为了自学信号量和 POSIX 共享内存。
这个想法是一个程序,服务器,打开共享内存并向其中写入一个结构(包含一个信号量和一个数组)。然后它等待输入并在输入后增加信号量。
同时客户端打开共享内存,等待信号量,待服务器自增后,读取结构
服务器似乎工作正常,但是我在客户端的 sem_wait
函数中立即遇到段错误(甚至在服务器递增它之前)。我不知道哪里出了问题。
服务器代码:
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <semaphore.h>
#include <stdbool.h>
#define ARRAY_MAX 1024
typedef struct {
sem_t inDataReady;
float array[ARRAY_MAX];
unsigned arrayLen;
} OsInputData;
int main() {
int shm_fd;
OsInputData *shm_ptr;
if((shm_fd = shm_open("/my_shm", O_CREAT | O_RDWR, 0666)) == -1) {
printf("shm_open failure\n");
return 1;
}
if(ftruncate(shm_fd, sizeof(OsInputData)) == -1) {
printf("ftruncate failure\n");
return 1;
}
if((shm_ptr = (OsInputData*)mmap(0, sizeof(OsInputData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
printf("mmap failure\n");
return 1;
}
sem_init(&(shm_ptr->inDataReady), true, 0);
shm_ptr->array[0] = 3.0;
shm_ptr->array[1] = 1.0;
shm_ptr->array[2] = 2.0;
shm_ptr->array[3] = 5.0;
shm_ptr->array[4] = 4.0;
shm_ptr->arrayLen = 5;
getchar();
sem_post(&(shm_ptr->inDataReady));
sem_destroy(&(shm_ptr->inDataReady));
munmap(shm_ptr, sizeof(OsInputData));
close(shm_fd);
return 0;
}
客户代码:
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <semaphore.h>
#include <stdbool.h>
#define ARRAY_MAX 1024
typedef struct {
sem_t inDataReady;
float array[ARRAY_MAX];
unsigned arrayLen;
} OsInputData;
int main() {
int shm_fd;
OsInputData *shm_ptr;
if((shm_fd = shm_open("/my_shm", O_RDONLY, 0666)) == -1) {
printf("shm_open failure\n");
return 1;
}
if((shm_ptr = (OsInputData*)mmap(0, sizeof(OsInputData), PROT_READ, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
printf("mmap failure\n");
return 1;
}
sem_wait(&(shm_ptr->inDataReady));
printf("%u\n", shm_ptr->arrayLen);
munmap(shm_ptr, sizeof(OsInputData));
close(shm_fd);
return 0;
}
实际结果取决于您的系统,但通常您的程序包含错误。你不能破坏另一个 process/thread 可以到达的信号量。仅仅因为你执行了 sem_post 并不意味着你的系统已经切换到等待它的进程。当你毁掉它的时候,另一个人可能还在使用它。
SIGSEGV,在这种情况下,是一种善意。很少有程序员会检查 sem_wait 的 return 值,这可能导致程序认为它们是同步的,而实际上它们不是。
原来我必须在客户端中打开共享内存,同时具有读写权限,并相应地更新 mmap
中的保护。
相当愚蠢的错误,因为很明显客户端也需要写权限才能实际修改信号量。
因此在客户端代码中进行以下更改解决了它
...
shm_fd = shm_open("/my_shm", O_CREAT | O_RDWR, 0755)
...
shm_ptr = (OsInputData*)mmap(0, sizeof(OsInputData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0)
...