Unix下利用fork()与共享内存实现结构体数组跨进程访问的技术咨询
Hey there! Let's break down the issues in your current code and walk through the correct implementation steps to get your 10-element strProcess array into shared memory for client access.
First: Fix Critical Syntax Errors
Your code has a few syntax issues that will prevent it from compiling at all:
- Function definitions inside
main(): C doesn't allow defining functions inside another function. Movefinval,frand, andfsortascoutside ofmain()entirely. - Broken
shmatusage: Your code has invalid pointer assignment and error checking for shared memory attachment. Replace those lines with:struct strProcess *shm_array = (struct strProcess *)shmat(nShmid, NULL, 0); if (shm_array == (void *)-1) { perror("shmat"); exit(1); } - Wrong shared memory size:
sizeof(pArray) * 10doubles the required size (sincepArrayis already a 10-element array). Usesizeof(struct strProcess) * 10or justsizeof(pArray)to get the correct size for 10strProcessstructs. - Uninitialized random seed:
rand()will generate the same sequence every time unless you initialize it withsrand(time(NULL));at the start ofmain().
Next: Fix Logical Flaws
These issues will cause unexpected behavior even if the code compiles:
- Child processes don't exit: After writing to shared memory, child processes will continue executing the rest of
main()(like sorting and file writes). Addexit(0);at the end of the child process block to prevent this. - Confusing stack array with shared memory: You're writing to shared memory in child processes but sorting the stack-based
pArray(which isn't connected to shared memory). Sort the shared memory pointer (shm_array) instead. - Log file race conditions: Multiple child processes writing to
logfile.txtat the same time can garble output. Either let the parent process handle all logging, or add a file lock (simpler to stick with parent-side logging).
Key Implementation Principles for Shared Memory + fork()
Let's cover the core concepts to make this work reliably:
- Shared Memory Lifecycle:
- Use
shmget()to create a segment with a unique key (useftok()instead of a hardcoded key if you want better reliability across systems). shmat()attaches the segment to your process's address space; all child processes fromfork()inherit this attachment, so they can directly access the shared memory.- Don't forget to clean up: use
shmdt()to detach when done, andshmctl(nShmid, IPC_RMID, NULL)to delete the segment (skip deletion if your client still needs access).
- Use
- Synchronization:
If multiple processes (parent + children, or client + your server) are reading/writing shared memory, use semaphores (viasemget()/semop()) to lock access and avoid data corruption. For your current setup, waiting for all children to exit before sorting (usingwait()) avoids most races. - Client Access:
For a client to read the shared memory, it just needs to:- Use the same key to call
shmget() - Attach with
shmat()to get thestrProcesspointer - Read/write the array, then detach with
shmdt()
- Use the same key to call
Corrected Full Code
Here's the fixed version of your code with all the above changes applied:
// Compiler Directives // Standard Library Inclusions #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <unistd.h> #include <time.h> #include <sys/wait.h> //Other Inclusions struct strProcess { int nPriority; int nPid; }; // Function Prototypes int frand(int nInput); int finval(int nInput); void fsortasc(struct strProcess pArray[], int nInput); // Function Definitions int finval(int nInput) { while(nInput <= 0 || nInput > 10) { printf("please enter a number between 1 and 10 \n"); scanf("%d", &nInput); } return nInput; } int frand(int nInput) { int nRand; nRand = (rand() % nInput) + 1; return nRand; } void fsortasc(struct strProcess pArray[], int nInput) { struct strProcess temp; int i, j; for (i = 0; i < nInput - 1; i++) { for (j = 0; j < (nInput - 1 - i); j++) { if (pArray[j].nPriority > pArray[j + 1].nPriority) { temp = pArray[j]; pArray[j] = pArray[j + 1]; pArray[j + 1] = temp; } } } } // Main int main(void) { // Variable Declarations int nShmid, i, nInput; key_t nKey = 5678; pid_t pid; struct strProcess *shm_array; const int MAX_PROCESSES = 10; // Initialize random seed for unique priorities srand(time(NULL)); // Open log file FILE *f = fopen("logfile.txt", "w"); if (f == NULL) { printf("Error opening file!\n"); exit(1); } // Get valid process count input printf("please enter the amount of processes to create for this cycle between 1 and 10 \n"); scanf("%d", &nInput); if (nInput <= 0 || nInput > 10) { nInput = finval(nInput); } printf("Creating %d processes\n", nInput); fprintf(f, "Creating %d processes\n", nInput); // Calculate shared memory size for 10 strProcess structures int nSize = sizeof(struct strProcess) * MAX_PROCESSES; // Create shared memory segment (read/write for all users) if ((nShmid = shmget(nKey, nSize, IPC_CREAT | 0666)) < 0) { perror("shmget"); fclose(f); exit(1); } printf("Shared memory segment created (ID: %d)\n", nShmid); fprintf(f, "Shared memory segment created (ID: %d)\n", nShmid); // Attach shared memory to current process address space shm_array = (struct strProcess *)shmat(nShmid, NULL, 0); if (shm_array == (void *)-1) { perror("shmat"); shmctl(nShmid, IPC_RMID, NULL); // Clean up segment on error fclose(f); exit(1); } printf("Shared memory segment attached\n"); fprintf(f, "Shared memory segment attached\n"); // Fork child processes to populate shared memory for (i = 0; i < nInput; i++) { if ((pid = fork()) < 0) { perror("fork"); // Clean up resources on fork failure shmdt(shm_array); shmctl(nShmid, IPC_RMID, NULL); fclose(f); exit(1); } if (pid == 0) { // Child process logic shm_array[i].nPid = getpid(); int nRpriority = frand(nInput); shm_array[i].nPriority = nRpriority; printf("Print job created with Pid %d and priority number %d\n", getpid(), nRpriority); exit(0); // Exit child to avoid executing parent code } } // Wait for all child processes to finish writing to shared memory for (i = 0; i < nInput; i++) { wait(NULL); } // Sort the shared memory array by priority (ascending order) fsortasc(shm_array, nInput); printf("\nSorted processes by priority:\n"); fprintf(f, "\nSorted processes by priority:\n"); for (i = 0; i < nInput; i++) { printf("Pid: %d, Priority: %d\n", shm_array[i].nPid, shm_array[i].nPriority); fprintf(f, "Pid: %d, Priority: %d\n", shm_array[i].nPid, shm_array[i].nPriority); } fprintf(f, "%d processes have been created and sorted\n", nInput); // Detach shared memory from current process shmdt(shm_array); // Uncomment the line below to delete the segment immediately (skip if client needs access) // shmctl(nShmid, IPC_RMID, NULL); fclose(f); return 0; }
Quick Notes for Client Access
To let a client read the shared memory:
- Use the same
key_t nKey = 5678; - Call
shmget(nKey, sizeof(struct strProcess)*10, 0666)to get the segment ID - Attach with
struct strProcess *client_shm = (struct strProcess *)shmat(shmid, NULL, 0); - Access
client_shm[i]to read eachstrProcessentry - Detach with
shmdt(client_shm);when done
内容的提问来源于stack exchange,提问作者iAnwar
相关产品推荐
相关产品推荐

