如何从 child 进程更新共享数据?
How do I update shared data from a child process?
我正在尝试制作一个分叉 5 children 的程序。 children all access shared memory to read in a number and increase it by 1 until the number reaches 100. children 能够读入共享内存中的值,但它们没有更新它。我做错了什么?
#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);
}
}
}
最明显的问题是:
sprintf(newNumString, "%i", origNum);
从 'old' 值设置 'new' 字符串,因此共享内存中的数据永远不会更新为 'new' 值。
但是,还有其他几个问题涉及 'race' 条件。
这可以通过具有 'share' 属性的互斥锁来纠正。
注意:没有 'shared' 属性,多个进程访问同一个互斥量是未定义的行为。
警告:我没有包括检查调用系统函数的所有返回值,尤其是那些处理互斥锁设置的函数。您应该添加该检查。
警告:我没有包含破坏互斥锁的代码。您应该添加该声明。
警告:我没有包含释放内存映射内存的代码。您应该添加该声明。
存在子进程未全部退出就退出父进程的问题。这导致僵尸进程,而子进程曾经是。
有'problem'使用'magic'号。 'magic' 数字使代码更难理解、调试等。
在下面的代码中,我记录了为什么要包含每个头文件。这使得某些活动更容易完成。
我留下了一些原始代码(注释掉)来说明一些更改。
我在需要时使用了 'cast',以避免来自编译器的 'implicit conversion' 警告( gcc
on linux )
以下代码更正了问题,包括问题评论中列出的问题。
#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, '[=11=]', 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 ] = {'[=11=]'};
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
我正在尝试制作一个分叉 5 children 的程序。 children all access shared memory to read in a number and increase it by 1 until the number reaches 100. children 能够读入共享内存中的值,但它们没有更新它。我做错了什么?
#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);
}
}
}
最明显的问题是:
sprintf(newNumString, "%i", origNum);
从 'old' 值设置 'new' 字符串,因此共享内存中的数据永远不会更新为 'new' 值。
但是,还有其他几个问题涉及 'race' 条件。 这可以通过具有 'share' 属性的互斥锁来纠正。
注意:没有 'shared' 属性,多个进程访问同一个互斥量是未定义的行为。
警告:我没有包括检查调用系统函数的所有返回值,尤其是那些处理互斥锁设置的函数。您应该添加该检查。
警告:我没有包含破坏互斥锁的代码。您应该添加该声明。
警告:我没有包含释放内存映射内存的代码。您应该添加该声明。
存在子进程未全部退出就退出父进程的问题。这导致僵尸进程,而子进程曾经是。
有'problem'使用'magic'号。 'magic' 数字使代码更难理解、调试等。
在下面的代码中,我记录了为什么要包含每个头文件。这使得某些活动更容易完成。
我留下了一些原始代码(注释掉)来说明一些更改。
我在需要时使用了 'cast',以避免来自编译器的 'implicit conversion' 警告( gcc
on linux )
以下代码更正了问题,包括问题评论中列出的问题。
#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, '[=11=]', 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 ] = {'[=11=]'};
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