我有一个 C 应用程序,其中一个进程将数据加载到共享内存空间,然后另一个进程访问共享内存以进行进一步处理。 进程 1 运行良好并加载数据,但进程 2 在共享内存结构字段中看到 0。
使用 GDB,我可以看到在进程 1 结束时,数据已加载到共享内存中并且可以访问。但是,当我尝试从第二个进程访问共享内存时,它显示为 0s。
为了分析,我尝试在两个终端上同时使用 GDB 查看共享内存字段,一个在进程 1 的末尾(就在退出 main 之前),当所有数据都已加载时,同时在另一个终端上使用 GDB进程 2 查看共享内存字段。
以下是我找到的-
进程 1 --> 加载共享内存并在程序结束时(退出 main 之前),在 GDB 中,我看到共享内存中的结构已填充
##Address pointed by the dnodes structure pointer
(gdb) x /10xg &(g_ptr->dct_tu->dnodes)
0x7fff56fbe4b0: 0x00007fff859abc88 0x00007fffbfaee688
0x7fff56fbe4c0: 0x00007fffbfcd6b08 0x00007fffbe591a88
0x7fff56fbe4d0: 0x00007fffbf4d3e88 0x00007fffbfd9a008
0x7fff56fbe4e0: 0x00007fffed264e08 0x00007fffb2e76a88
0x7fff56fbe4f0: 0x00007fffb6b7fa88 0x00007fffb7320c88
##Data at the address 0x7fff859abc88 which is where the dnodes pointer points as in the above screenshot
(gdb) x /100dw &(g_ptr->dct_tu->dnodes[0])
0x7fff859abc88: 0 0 68068068 0
0x7fff859abc98: 68068068 0 0 0
0x7fff859abca8: 0 0 68067 0
0x7fff859abcb8: 76066071 0 87078000 0
0x7fff859abcc8: 1575397555 319731 0 0
0x7fff859abcd8: 77066 0 76066066 0
0x7fff859abce8: 87088000 0 1575397556 319731
进程 2 --> 试图访问进程 1 创建的共享内存 内存地址与进程 1 指向的内存地址匹配,但值全为 0。
##Address pointed by the dnodes structure pointer
(gdb) x /10xg &(shmp->dct_tu->dnodes)
0x7fff5711e4b0: 0x00007fff859abc88 0x00007fffbfaee688
0x7fff5711e4c0: 0x00007fffbfcd6b08 0x00007fffbe591a88
0x7fff5711e4d0: 0x00007fffbf4d3e88 0x00007fffbfd9a008
0x7fff5711e4e0: 0x00007fffed264e08 0x00007fffb2e76a88
0x7fff5711e4f0: 0x00007fffb6b7fa88 0x00007fffb7320c88
##Data at the address 0x7fff859abc88 which is where the dnodes pointer points as in the above screenshot
(gdb) x /100dw &(shmp->dct_tu->dnodes[0])
0x7fff859abc88: 0 0 0 0
0x7fff859abc98: 0 0 0 0
0x7fff859abca8: 0 0 0 0
0x7fff859abcb8: 0 0 0 0
0x7fff859abcc8: 0 0 0 0
0x7fff859abcd8: 0 0 0 0
0x7fff859abce8: 0 0 0 0
0x7fff859abcf8: 0 0 0 0
0x7fff859abd08: 0 0 0 0
进程1代码- 简化过程 1 代码,如果在 main 函数结束时在 GDB 中检查,则填充链接和 dnodes 结构。此 C 文件中包含头文件“appheader.h”结构
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
#define N_LINKAGE_NODES_TU 1000
#define N_DATA_NODES_TU 100
#define arraySize 36+1
typedef struct linkage_node_tu
{
long link[10];
} ln_node_t_tu;
typedef struct data_node_tu
{
unsigned long code;
unsigned long sales_account_up;
unsigned long sales_account_lo;
long acc_num_tu;
long link;
} d_node_t_tu;
typedef struct dc_tree_tu
{
ln_node_t_tu *links;
d_node_t_tu *dnodes;
} dc_tree_t_tu;
typedef struct par_refdata
{
dc_tree_t_tu dct_tu;
} par_refdata_type;
typedef struct lookup_dict
{
int iIndex;
char cCharRep;
} lkup_dict;
extern void load_refdata ();
void load_lookup_array();
long convertAccToLong(char *);
int debug;
lkup_dict lookup_d[arraySize];
int main (int argc, char **argv)
{
int i;
int shmget_flag = (IPC_CREAT | IPC_EXCL | 0600);
int shm_par_refdata_id;
size_t total_shmem_size;
size_t g_size;
size_t tu_l_size;
size_t tu_d_size;
char *start_shmem_address;
par_refdata_type *g_ptr;
ln_node_t_tu *tu_l_ptr;
d_node_t_tu *tu_d_ptr;
char *e_ptr;
char *end_shmem_address;
debug = 1;
g_size = sizeof(par_refdata_type);
tu_l_size = (sizeof(ln_node_t_tu) * N_LINKAGE_NODES_TU);
tu_d_size = (sizeof(d_node_t_tu) * N_DATA_NODES_TU);
total_shmem_size = g_size + tu_l_size + tu_d_size;
if (debug)
{
printf("PROCESS1_SHM : g_size = %lu\n", g_size);
printf("PROCESS1_SHM : tu_l_size = %lu\n", tu_l_size);
printf("PROCESS1_SHM : tu_d_size = %lu\n", tu_d_size);
printf("PROCESS1_SHM : total_shmem_size = %lu\n", total_shmem_size);
printf("PROCESS1_SHM : N_LINKAGE_NODES_TU <%d>, sizeof(ln_node_t_tu) <%zu>\n",N_LINKAGE_NODES_TU, sizeof(ln_node_t_tu));
}
//set up Shared mem
shm_par_refdata_id = shmget( 0x2a0e4150,total_shmem_size,shmget_flag);
if (shm_par_refdata_id == -1)
{
printf("PROCESS1_SHM : unable to shmget gather refdata, errno = %d ", errno);
exit (EXIT_FAILURE);
}
if((start_shmem_address = shmat (shm_par_refdata_id,0,0)) == (void *)-1)
{
printf("unable to shmat gather refdata, errno = %d ",errno);
exit (EXIT_FAILURE);
}
end_shmem_address = start_shmem_address + total_shmem_size;
printf("PROCESS1_SHM : start_shmem_address = %u\n", start_shmem_address);
printf("PROCESS1_SHM : end_shmem_address = %u\n", end_shmem_address);
printf("PROCESS1_SHM : total_shmem_size = %lu\n", total_shmem_size);
//Initialize the pointers to the various structures in shared memory
g_ptr = (par_refdata_type *) start_shmem_address;
tu_l_ptr = (ln_node_t_tu *)(intptr_t)((unsigned long)g_ptr + (unsigned long)g_size);
tu_d_ptr = (d_node_t_tu *)(intptr_t)((unsigned long)tu_l_ptr + (unsigned long)tu_l_size);
e_ptr = (char *)(intptr_t)((unsigned long)tu_d_ptr + (unsigned long)tu_d_size);
(g_ptr->dct_tu).links=tu_l_ptr;
(g_ptr->dct_tu).dnodes=tu_d_ptr;
if (debug)
{
printf("PROCESS1_SHM : g_ptr = %u\n", g_ptr);
printf("PROCESS1_SHM : tu_l_ptr = %u\n", tu_l_ptr);
printf("PROCESS1_SHM : tu_d_ptr = %u\n", tu_d_ptr);
printf("PROCESS1_SHM : e_ptr = %u\n", e_ptr);
}
if(e_ptr > (start_shmem_address + total_shmem_size))
{
printf("Shared memory required exceeds shared memory requested-Exiting ");
exit (EXIT_FAILURE);
}
/*Load the shared memory with the reference data */
load_refdata (start_shmem_address);
exit (EXIT_SUCCESS);
} /* main */
void load_refdata( par_refdata_type *g_ptr)
{
FILE *fp;
long cur_dnode;
long cur_lnode;
long nxt_lnode;
long free_lnode;
long last_lnode;
long new_addr;
long free_dnode;
unsigned long tu_code;
char cli[100];
int cli_len;
int discard;
int rec_cnt;
int digit;
long val;
char tu_char[3];
int code_val;
unsigned long tu_sales_up;
unsigned long tu_sales_lo;
char sales_char[7];
long sales_val_up;
long sales_val_lo;
long sales_acc_int;
dc_tree_t_tu *dt_ptr_tu;
char cd_ref_file[100];
char lbuf[BUFSIZ];
int records_read;
char csAccNum[16];
long llaccntNum;
llaccntNum=0ll;
load_lookup_array();
strcpy(cd_ref_file, "/c/projects/refdat");
if ((fp = fopen(cd_ref_file,"r")) == NULL)
{
printf("open failed for %s (errno=%d)",cd_ref_file, errno);
exit (EXIT_FAILURE);
}
dt_ptr_tu = &(g_ptr->dct_tu);
/* Initialize structures */
for (cur_lnode = 0; cur_lnode < N_LINKAGE_NODES_TU; cur_lnode++)
{
for (digit = 0; digit < 10; digit++)
{
dt_ptr_tu->links[cur_lnode].link[digit] = 0;
}
}
sales_acc_int = 68068068;
for (cur_dnode = 0; cur_dnode < N_DATA_NODES_TU; cur_dnode++)
{
dt_ptr_tu->dnodes[cur_dnode].code = 0;
dt_ptr_tu->dnodes[cur_dnode].link = 0;
dt_ptr_tu->dnodes[cur_dnode].acc_num_tu = 0ll;
dt_ptr_tu->dnodes[cur_dnode].sales_account_up = sales_acc_int;
dt_ptr_tu->dnodes[cur_dnode].sales_account_lo = sales_acc_int;
}
free_lnode = 1;
free_dnode = 1;
rec_cnt = 0;
records_read = 0;
while (records_read < N_DATA_NODES_TU && fgets(lbuf, sizeof(lbuf), fp) != NULL)
{
//E.g. lines from file -> 0012345670 DX LBRZ1 WX11237882
sscanf(lbuf, "%s %s %s %s", cli, tu_char,sales_char, csAccNum);
rec_cnt++;
records_read++ ;
code_val=tu_char[0]*1000+tu_char[1];
sales_val_up= sales_char[0]*1000000 + sales_char[1]*1000 + sales_char[2];
sales_val_lo= sales_char[3]*1000000 + sales_char[4]*1000 + sales_char[5];
llaccntNum=convertAccToLong(csAccNum);
tu_code = code_val;
tu_sales_up = sales_val_up;
tu_sales_lo = sales_val_lo;
cli_len = strlen(cli);
cur_lnode = 0;
last_lnode = 0;
discard = 0;
for (digit = 0; (digit < cli_len) && (discard == 0); digit++)
{
val = cli[digit] - '0';
new_addr = dt_ptr_tu->links[cur_lnode].link[val];
if (new_addr < 0)
{
cur_dnode = -new_addr;
if (digit == (cli_len - 1))
{
if (tu_code != dt_ptr_tu->dnodes[cur_dnode].code)
{
discard = 1;
printf("duplicate tu found %ld",tu_code);
}
continue;
}
if (dt_ptr_tu->dnodes[cur_dnode].link == 0)
{
if (free_lnode == N_LINKAGE_NODES_TU)
{
fclose(fp);
printf("Out of LNODES for TU at record %d",rec_cnt);
return;
}
dt_ptr_tu->dnodes[cur_dnode].link= free_lnode++;
}
nxt_lnode = dt_ptr_tu->dnodes[cur_dnode].link;
cur_lnode = nxt_lnode;
continue;
}
if (new_addr == 0)
{
if (free_lnode == N_LINKAGE_NODES_TU)
{
fclose(fp);
printf("Out of LNODES for TU at record %d",rec_cnt);
return;
}
nxt_lnode = free_lnode++;
dt_ptr_tu->links[last_lnode].link[val] = nxt_lnode;
last_lnode = cur_lnode;
cur_lnode = nxt_lnode;
continue;
}
cur_lnode = new_addr;
}
if (discard == 1)
{
printf("Duplicate cli %s at line %d",cli,rec_cnt);
}
else
{
if (free_dnode == N_DATA_NODES_TU)
{
fclose(fp);
printf("Out of DNODES for TU at record %d",rec_cnt);
return;
}
dt_ptr_tu->dnodes[free_dnode].code = tu_code;
dt_ptr_tu->dnodes[free_dnode].sales_account_up = tu_sales_up;
dt_ptr_tu->dnodes[free_dnode].sales_account_lo = tu_sales_lo;
dt_ptr_tu->dnodes[free_dnode].acc_num_tu = llaccntNum;
dt_ptr_tu->links[last_lnode].link[val] = -free_dnode;
free_dnode++;
free_lnode--;
}
}
fclose(fp);
return;
}
long convertAccToLong(char *csAccNum)
{
int i, j;
long out=0ll;
for ( i=strlen(csAccNum)-1; i >= 0 ; i--)
{
for ( j=0; j < arraySize-1 ; j++)
{
if (lookup_d[j].cCharRep == csAccNum[i])
{
out += (lookup_d[j].iIndex * pow(36,(strlen(csAccNum)-1 - i)));
break;
}
}
}
if ( out > 9223372036854775807ll )
printf("out <%ld> for acc <%s>\n",out, csAccNum);
return out;
}
void load_lookup_array()
{
int i;
char charArray[arraySize];
strcpy(charArray,"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
for ( i=0; i < arraySize ; i++)
{
lookup_d[i].iIndex=i;
lookup_d[i].cCharRep=charArray[i];
}
}
进程2代码- 进程 2 代码访问由进程 1 填充的共享内存。一旦连接了共享内存,在 GDB 中使用它来检查共享内存字段。
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#include"appheader.h"
#define BUF_SIZE 2962799112
#define SHM_KEY 0x2a0e4150
struct shmseg {
int cnt;
int complete;
char buf[BUF_SIZE];
};
int main(int argc, char *argv[]) {
int shmid;
gather_refdata_type *shmp;
shmid = shmget(SHM_KEY, SHM_DATA_SIZE, 0600);
if (shmid == -1) {
perror("Shared memory get failed");
return 1;
}
shmp = shmat(shmid, NULL, 0);
if (shmp == (void *) -1) {
perror("Shared memory attach failed");
return 1;
}
printf("shmp->dct_tu.links->link[0] <%ld>\n",*(shmp->dct_tu.links->link[0]));
printf("Reading Process: Reading Done, Detaching Shared Memory\n");
return 0;
}
ipcs命令输出-
$ ipcs
------ Message Queues --------
key msqid owner perms used-bytes messages
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x2a0e4150 0 dev01 600 2962799112 2
------ Semaphore Arrays --------
key semid owner perms nsems
我无法理解为什么相同的内存地址在进程 1 访问时似乎已填充,但同时在进程 2 查看时似乎为 0。