如何在 C 中的进程之间共享一个带有指针的结构?
How can I share a struct with pointers between processes in C?
我正在尝试将文件放入结构中,但在共享内存时遇到问题,因为我可以访问创建的进程中发生映射但无法访问数组的字段(只能访问 int ) 在其他进程中。我尝试了很多不同的方法,但我接下来介绍的方法对我来说更有意义,因为我正在使用 shmget 以正确的方式分配内存。
为清楚起见:唯一共享的是整数 lim_thread。其他字段位于我无法访问的内存区域。为什么?
如我所见,指针指向共享的内存区域。
configs.txt:
Threads = 5
Domains = uc.pt; edu
LocalDomain = so.local
NamedPipeEstatisticas = statistics
结构:
typedef struct configs
{
int lim_thread;
char (*valid_domains)[MAX_DOMAIN_SIZE]; //max size for valid domains
char *domain;
char *stat_pipe;
sem_t sem;
} CONFIGS;
main.c:
/*Shared memory for configs*/
CONFIGS *_configs;
int _shmid_configs;
int main(int argc, char *argv[]) {
pid_t config_pid; //will hold the configuration process id
_shmid_configs = shmget(IPC_PRIVATE, sizeof(CONFIGS), IPC_CREAT|0666);
_configs = shmat(_shmid_configs, NULL, 0);
/*Semaphores*/
sem_init( &( _configs->sem), 1, 0);
//initializes processes
if( ( config_pid = fork() ) < 0) {
perror("Failed creating configuration manager process");
num_forks++;
}
else if( config_pid == 0 ) {
init_config();
exit(0);
}
sem_wait(&(_configs->sem));
/////////////////////////DEBUG////////////////////////////////
printf("%d\n", _configs->lim_thread);
printf("%s\n", *(_configs->valid_domains+1));
printf("%s\n", _configs->domain);
printf("%s\n", _configs->stat_pipe);
//////////////////////////////////////////////////////////////
return 0;
}
configs.c
#define MAX_LINE_SIZE 1000
int init_config() {
FILE *fp;
char domains[MAX_LINE_SIZE], line[MAX_LINE_SIZE], *saveptr, *aux_char;
int count = 0, aux;
int temp_shmid;
if( ( fp = fopen( "./configs.txt", "r")) == NULL) {
perror("Failed to open configs.txt");
return -1;
}
fscanf( fp,"Threads = %d\n", &(_configs->lim_thread));
//To start reading "Domains = "
fscanf(fp, "Domains = ");
fgets(domains, MAX_LINE_SIZE, fp);
domains[strlen(domains) -1] = '[=13=]';
//counts the number of domains
for(aux = 0; aux < strlen(domains); aux++) {
if( domains[aux] == ';' ) {
count++;
}
}
//creates shared memory for the valid domains
temp_shmid = shmget(IPC_PRIVATE, (count+1) * sizeof( char[MAX_DOMAIN_SIZE]), IPC_CREAT|0666);
_configs->valid_domains = shmat( temp_shmid, NULL, 0);
//copies all the data to the struct
strcpy( *(_configs->valid_domains), strtok_r(domains, "; ", &saveptr) );
aux = 1;
while( ( aux_char = strtok_r( NULL, "; ", &saveptr) ) != NULL) {
strcpy( *(_configs->valid_domains + aux), aux_char);
aux++;
}
fscanf(fp, "LocalDomain = %s\n", line);
temp_shmid = shmget(IPC_PRIVATE, (strlen(line) + 1) * sizeof(char), IPC_CREAT|0660);
_configs->domain = (char*)shmat(temp_shmid, NULL, 0);
strcpy(_configs->domain, line);
fscanf(fp, "NamedPipeEstatisticas = %s\n", line);
temp_shmid = shmget( IPC_PRIVATE, (strlen(line) +1) * sizeof(char), IPC_CREAT|0660);
_configs->stat_pipe = (char*)shmat(temp_shmid, NULL, 0);
strcpy(_configs->stat_pipe, line);
fclose(fp);
sem_post( &(_configs->sem));
/////////////////////////DEBUG////////////////////////////////
printf("%d\n", _configs->lim_thread);
printf("%s\n", *(_configs->valid_domains+1));
printf("%s\n", _configs->domain);
printf("%s\n", _configs->stat_pipe);
//////////////////////////////////////////////////////////////
return 0;
}
正如 kaylum 所指出的,每个进程都可能将共享内存块映射到不同的虚拟地址。因此指针不能共享,你需要使用偏移量。
分配一个共享内存块,将其分为两部分:table 内容区和数据区。 table 内容由包含值或(而不是指针)的变量组成,共享内存块开始与数据区内数据元素开始之间的偏移量。
然后,为了获得数据元素的地址,进程只需将其偏移量添加到其地址 space 中共享内存块的地址即可。
你可以做你想做的事。只需在 main process/thread 创建任何线程之前完成所有 shmget/shmat
。
子级将继承指针,所有线程的值都相同(例如,指针是 全局。也就是说,它们是不是 使用 _thread
并且不在线程本地存储中)。
这很好用。我已经在 50 多个线程的系统中使用它并且效果很好
我正在尝试将文件放入结构中,但在共享内存时遇到问题,因为我可以访问创建的进程中发生映射但无法访问数组的字段(只能访问 int ) 在其他进程中。我尝试了很多不同的方法,但我接下来介绍的方法对我来说更有意义,因为我正在使用 shmget 以正确的方式分配内存。
为清楚起见:唯一共享的是整数 lim_thread。其他字段位于我无法访问的内存区域。为什么? 如我所见,指针指向共享的内存区域。
configs.txt:
Threads = 5
Domains = uc.pt; edu
LocalDomain = so.local
NamedPipeEstatisticas = statistics
结构:
typedef struct configs
{
int lim_thread;
char (*valid_domains)[MAX_DOMAIN_SIZE]; //max size for valid domains
char *domain;
char *stat_pipe;
sem_t sem;
} CONFIGS;
main.c:
/*Shared memory for configs*/
CONFIGS *_configs;
int _shmid_configs;
int main(int argc, char *argv[]) {
pid_t config_pid; //will hold the configuration process id
_shmid_configs = shmget(IPC_PRIVATE, sizeof(CONFIGS), IPC_CREAT|0666);
_configs = shmat(_shmid_configs, NULL, 0);
/*Semaphores*/
sem_init( &( _configs->sem), 1, 0);
//initializes processes
if( ( config_pid = fork() ) < 0) {
perror("Failed creating configuration manager process");
num_forks++;
}
else if( config_pid == 0 ) {
init_config();
exit(0);
}
sem_wait(&(_configs->sem));
/////////////////////////DEBUG////////////////////////////////
printf("%d\n", _configs->lim_thread);
printf("%s\n", *(_configs->valid_domains+1));
printf("%s\n", _configs->domain);
printf("%s\n", _configs->stat_pipe);
//////////////////////////////////////////////////////////////
return 0;
}
configs.c
#define MAX_LINE_SIZE 1000
int init_config() {
FILE *fp;
char domains[MAX_LINE_SIZE], line[MAX_LINE_SIZE], *saveptr, *aux_char;
int count = 0, aux;
int temp_shmid;
if( ( fp = fopen( "./configs.txt", "r")) == NULL) {
perror("Failed to open configs.txt");
return -1;
}
fscanf( fp,"Threads = %d\n", &(_configs->lim_thread));
//To start reading "Domains = "
fscanf(fp, "Domains = ");
fgets(domains, MAX_LINE_SIZE, fp);
domains[strlen(domains) -1] = '[=13=]';
//counts the number of domains
for(aux = 0; aux < strlen(domains); aux++) {
if( domains[aux] == ';' ) {
count++;
}
}
//creates shared memory for the valid domains
temp_shmid = shmget(IPC_PRIVATE, (count+1) * sizeof( char[MAX_DOMAIN_SIZE]), IPC_CREAT|0666);
_configs->valid_domains = shmat( temp_shmid, NULL, 0);
//copies all the data to the struct
strcpy( *(_configs->valid_domains), strtok_r(domains, "; ", &saveptr) );
aux = 1;
while( ( aux_char = strtok_r( NULL, "; ", &saveptr) ) != NULL) {
strcpy( *(_configs->valid_domains + aux), aux_char);
aux++;
}
fscanf(fp, "LocalDomain = %s\n", line);
temp_shmid = shmget(IPC_PRIVATE, (strlen(line) + 1) * sizeof(char), IPC_CREAT|0660);
_configs->domain = (char*)shmat(temp_shmid, NULL, 0);
strcpy(_configs->domain, line);
fscanf(fp, "NamedPipeEstatisticas = %s\n", line);
temp_shmid = shmget( IPC_PRIVATE, (strlen(line) +1) * sizeof(char), IPC_CREAT|0660);
_configs->stat_pipe = (char*)shmat(temp_shmid, NULL, 0);
strcpy(_configs->stat_pipe, line);
fclose(fp);
sem_post( &(_configs->sem));
/////////////////////////DEBUG////////////////////////////////
printf("%d\n", _configs->lim_thread);
printf("%s\n", *(_configs->valid_domains+1));
printf("%s\n", _configs->domain);
printf("%s\n", _configs->stat_pipe);
//////////////////////////////////////////////////////////////
return 0;
}
正如 kaylum 所指出的,每个进程都可能将共享内存块映射到不同的虚拟地址。因此指针不能共享,你需要使用偏移量。
分配一个共享内存块,将其分为两部分:table 内容区和数据区。 table 内容由包含值或(而不是指针)的变量组成,共享内存块开始与数据区内数据元素开始之间的偏移量。
然后,为了获得数据元素的地址,进程只需将其偏移量添加到其地址 space 中共享内存块的地址即可。
你可以做你想做的事。只需在 main process/thread 创建任何线程之前完成所有 shmget/shmat
。
子级将继承指针,所有线程的值都相同(例如,指针是 全局。也就是说,它们是不是 使用 _thread
并且不在线程本地存储中)。
这很好用。我已经在 50 多个线程的系统中使用它并且效果很好