我正在尝试制作一个分配5个孩子的程序。子节点都访问共享内存以读取数字并将其增加1直到数字达到100.子节点能够读取共享内存中的值,但它们不会更新它。我做错了什么?
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
#include <sched.h>
int main (int argc, char* argv[])
{
//create shared memory with children and copy into it the starting number 0
void* shmem = mmap(NULL, 4, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
char number[10] = "0";
memcpy(shmem, number, sizeof(number));
int i;
for(i = 0; i < 5; ++i)
{
int childPID = fork();
if(childPID == 0)
{
//read a number in from shared memory
int origNum = atoi(shmem);
if(origNum < 100)
{
int newNum = origNum + 1;
//cast the new number to a string to be sent to shared memory
char newNumString[10];
sprintf(newNumString, "%i", origNum);
//send the new number to shared memory
memcpy(shmem, newNumString, sizeof(newNumString));
printf("I'm child %i. PID: %i. PPID: %i. Read in: %i and printed out %i\n", (i + 1), getpid(), getppid(), origNum, newNum);
printf("Current value in shmem: %s\n", shmem);
//yield process to allow other processes to run
sched_yield();
}
else
{
exit(0);
}
}
else
{
printf("I'm a parent. PID: %i. Num: %s\n", getpid(), shmem);
}
}
}
答案 0 :(得分:2)
最明显的问题是:
sprintf(newNumString, "%i", origNum);
从'old'值设置'new'字符串,因此共享内存中的数据永远不会更新为'new'值。
然而,还有其他一些涉及“种族”条件的问题。 这可以通过具有'share'属性的互斥锁进行纠正。
注意:没有'shared'属性,访问相同互斥锁的多个进程是未定义的行为。
警告:我没有包括检查系统函数调用中的所有返回值,尤其是那些处理互斥锁设置的函数。您应该添加该检查。
警告:我没有包含破坏互斥锁的代码。你应该添加该声明。
警告:我没有包含释放内存映射内存的代码。你应该添加该声明。
在子进程全部退出之前存在退出父进程的问题。这导致Zombie进程,其中子进程曾经是。
使用“魔术”数字存在“问题”。 “魔术”数字使代码更难以理解,调试等。
在下面的代码中,我已经记录了为什么要包含每个头文件。这使得某些活动更容易实现。
我留下了一些原始代码(注释掉了)来说明一些变化。
我在需要时使用了'强制转换',以避免编译器发出“隐式转换”警告(linux上为gcc
)
以下代码更正了问题,包括问题评论中列出的问题。
#include <stdio.h> // printf(), perror(), sprintf()
#include <stdlib.h> // atoi(), exit(), EXIT_FAILURE
#include <sys/mman.h> // mmap(), MAP_FAILED
#include <string.h> // strcpy(), memset(),
#include <sched.h> // sched_yield()
#include <unistd.h> // fork(), pid_t, getpid(), getppid()
#include <pthread.h> // pthread_mutex_lock(),
// pthread_mutex_unlock(),
// pthread_mutexattr_init(),
// pthread_mutex_init(),
// pthread_mutexattr_setpshared(),
// PTHREAD_PROCESS_SHARED,
// pthread_mutex_t,
// pthread_mutexattr_t
#include <sys/types.h>
#include <sys/wait.h> // waitpid()
#define MAX_CHILDREN 5
#define MAX_NUM_LEN 10
struct shared
{
char number[ MAX_NUM_LEN ];
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
};
struct shared *shmem;
//int main (int argc, char* argv[])
int main( void )
{
//create shared memory with children and copy into it the starting number 0
if( MAP_FAILED == (shmem = (struct shared*)mmap(NULL, sizeof( struct shared), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0) ) )
{
perror( "mmap failed" );
exit( EXIT_FAILURE );
}
// implied else, mmap successful
//char number[10] = "0";
memset( shmem, '\0', sizeof( struct shared ) );
//memcpy(shmem, number, sizeof(number));
// setup the mutex, include the 'shared' attribute
pthread_mutexattr_init(&shmem->attr);
pthread_mutexattr_setpshared( &shmem->attr, PTHREAD_PROCESS_SHARED );
pthread_mutex_init(&shmem->mutex, &shmem->attr );
//int i;
pid_t childPID[ MAX_CHILDREN ] = {0};
for( int i = 0; i < 5; ++i )
{
childPID[i] = fork();
switch( childPID[i] )
{
case -1:
perror( "fork failed" );
break;
case 0:
{ // then child63
while( 1 )
{
pthread_mutex_lock( &shmem->mutex );
//read a number in from shared memory
int origNum = atoi( shmem->number );
if( origNum < 100 )
{
int newNum = origNum + 1;
//cast the new number to a string to be sent to shared memory
char newNumString[ MAX_NUM_LEN ] = {'\0'};
sprintf(newNumString, "%i", newNum);
//send the new number to shared memory
strcpy( &shmem->number[0], newNumString );
printf( "I'm child %i. PID: %i. PPID: %i. Read in: %i and printed out %i\n",
(i + 1),
getpid(),
getppid(),
origNum,
newNum );
printf( "Current value in shmem: %s\n", shmem->number );
// allow other processes to access the number in shared memory
pthread_mutex_unlock( &shmem->mutex );
//yield process to allow other processes to run
sched_yield();
}
else
{
// allow other processes to access the number in shared memory
pthread_mutex_unlock( &shmem->mutex );
exit(0);
}
}
}
break;
default:
// then parent
printf("I'm a parent. PID: %i. Num: %s\n", getpid(), (char*)shmem);
break;
} // end switch
} // end for each child
for( int i=0; i< MAX_CHILDREN; i++ )
{
int status;
if( -1 != childPID[i] )
{ // then child process exists
waitpid( childPID[i], &status, 0 );
}
}
} // end function: main
以下是更正程序输出的摘录:
I'm a parent. PID: 25961. Num:
I'm a parent. PID: 25961. Num: 1
I'm child 1. PID: 25962. PPID: 25961. Read in: 0 and printed out 1
I'm a parent. PID: 25961. Num: 1
Current value in shmem: 1
I'm child 2. PID: 25963. PPID: 25961. Read in: 1 and printed out 2
I'm a parent. PID: 25961. Num: 2
Current value in shmem: 2
I'm child 2. PID: 25963. PPID: 25961. Read in: 2 and printed out 3
Current value in shmem: 3
I'm a parent. PID: 25961. Num: 3
I'm child 4. PID: 25965. PPID: 25961. Read in: 3 and printed out 4
Current value in shmem: 4
...
I'm child 4. PID: 25965. PPID: 25961. Read in: 95 and printed out 96
Current value in shmem: 96
I'm child 3. PID: 25964. PPID: 25961. Read in: 96 and printed out 97
Current value in shmem: 97
I'm child 4. PID: 25965. PPID: 25961. Read in: 97 and printed out 98
Current value in shmem: 98
I'm child 3. PID: 25964. PPID: 25961. Read in: 98 and printed out 99
Current value in shmem: 99
I'm child 4. PID: 25965. PPID: 25961. Read in: 99 and printed out 100
Current value in shmem: 100