当前位置: 技术问答>linux和unix
请教一个关于多进程的问题?(主要关于进程共享数据)
来源: 互联网 发布时间:2015-11-25
本文导语: 下面一段简单的程序: int main() { int exp; if (fork() == 0) { exp = 10; printf("child exp:%dn",exp); } else { printf("father exp:%dn",exp); } } 当我用fork调用创建一个子进程时,linux在写时为子进程复制了一份父进...
下面一段简单的程序:
int main()
{
int exp;
if (fork() == 0)
{
exp = 10;
printf("child exp:%dn",exp);
}
else
{
printf("father exp:%dn",exp);
}
}
当我用fork调用创建一个子进程时,linux在写时为子进程复制了一份父进程的数据区。这时我的本意是
让子进程改变全局的exp值(也就是exp对于两个进程都是公有的),但实际上,子进程改变的是自身数据
区的exp副本的值,对父进程没有影响。也就是两个进程分别有一个exp变量。请问如何使两个进程访问的
都是同一个exp值?当然这只是个简单的例子,实际情况复杂的多,如果每个需要被多个进程访问的变量
或数据都需要通过共享内存、消息队列等方式来通讯的话,是不是太麻烦了?有没有更简单的方式?
例如,我在N个c文件,每个文件里都定义了一个变量会被若干个进程使用到,为了使每个变量对于各个进
程来说都是公共的,而不是每个进程都产生一个变量的副本,难道我要进行N次内存映射?或者在每次改
变一个变量时都要使用进程通讯方式来通知其它进程?当然,可以把这n个变量都定义成指针,然后在总
的父进程中为它们分配空间,这样每个副本得到的指针都是指向相同的空间。但还是觉得麻烦了,难道就
没有一种办法能像不同函数使用同样一个公有变量那样让不同的进程都使用一个公共的变量吗?那所谓的
进程同步还有什么用,反正每个进程都得到了一个副本,更改都是对副本进行的,并不影响其它进程。
这就是小弟的一些问题,我是个初学者,希望高手解答。我在其它一些操作系统中看到,被创建的进程可
以共享公有变量,只要做好进程同步就是了。而且linux中创建进程难道都是调用fork后,在里面跟一段
代码吗?有没有调用一个类似create函数,参数就是进程要执行的函数名之类的函数呢?
还有,我希望的是多进程,不想使用多线程的方式代替。
int main()
{
int exp;
if (fork() == 0)
{
exp = 10;
printf("child exp:%dn",exp);
}
else
{
printf("father exp:%dn",exp);
}
}
当我用fork调用创建一个子进程时,linux在写时为子进程复制了一份父进程的数据区。这时我的本意是
让子进程改变全局的exp值(也就是exp对于两个进程都是公有的),但实际上,子进程改变的是自身数据
区的exp副本的值,对父进程没有影响。也就是两个进程分别有一个exp变量。请问如何使两个进程访问的
都是同一个exp值?当然这只是个简单的例子,实际情况复杂的多,如果每个需要被多个进程访问的变量
或数据都需要通过共享内存、消息队列等方式来通讯的话,是不是太麻烦了?有没有更简单的方式?
例如,我在N个c文件,每个文件里都定义了一个变量会被若干个进程使用到,为了使每个变量对于各个进
程来说都是公共的,而不是每个进程都产生一个变量的副本,难道我要进行N次内存映射?或者在每次改
变一个变量时都要使用进程通讯方式来通知其它进程?当然,可以把这n个变量都定义成指针,然后在总
的父进程中为它们分配空间,这样每个副本得到的指针都是指向相同的空间。但还是觉得麻烦了,难道就
没有一种办法能像不同函数使用同样一个公有变量那样让不同的进程都使用一个公共的变量吗?那所谓的
进程同步还有什么用,反正每个进程都得到了一个副本,更改都是对副本进行的,并不影响其它进程。
这就是小弟的一些问题,我是个初学者,希望高手解答。我在其它一些操作系统中看到,被创建的进程可
以共享公有变量,只要做好进程同步就是了。而且linux中创建进程难道都是调用fork后,在里面跟一段
代码吗?有没有调用一个类似create函数,参数就是进程要执行的函数名之类的函数呢?
还有,我希望的是多进程,不想使用多线程的方式代替。
|
我也不是很懂,简单谈下我的理解:
1.可以用linux的线程达到方便共享的目的.这里的线程是指使用clone系统调用创建的线程,而不是使用线程库得到的.通过传递给clone适当的参数,可以使新创建的进程和父进程共享虚拟地址,所以称为轻量级的进程(作为一个独立的实体被内核调度,pthread库创建的线程对内核而言是不可见的),这样的话就可以共享exp;
2.如果调用fork的话,你把需要共享的变量组织在一个文件中,然后操作文件是不是可以方便一些,没有试过,权当参考(你说的指针的方法可行吗,我觉得不可以,有时间试一下);
3.你说的进程同步的问题,我只有windows的经验,不好说,呵呵(能力有限啊,需要努力);
至于说类似于create的调用,在内核中有内核线程的概念,参数就是需要执行的函数.如果你要在用户空间中这样作,你可以fork后,直接调用你要用的函数就可以了.由于有写时拷贝的存在,这样做效率的损失应该也不大.
期待真正的高手的回答!
1.可以用linux的线程达到方便共享的目的.这里的线程是指使用clone系统调用创建的线程,而不是使用线程库得到的.通过传递给clone适当的参数,可以使新创建的进程和父进程共享虚拟地址,所以称为轻量级的进程(作为一个独立的实体被内核调度,pthread库创建的线程对内核而言是不可见的),这样的话就可以共享exp;
2.如果调用fork的话,你把需要共享的变量组织在一个文件中,然后操作文件是不是可以方便一些,没有试过,权当参考(你说的指针的方法可行吗,我觉得不可以,有时间试一下);
3.你说的进程同步的问题,我只有windows的经验,不好说,呵呵(能力有限啊,需要努力);
至于说类似于create的调用,在内核中有内核线程的概念,参数就是需要执行的函数.如果你要在用户空间中这样作,你可以fork后,直接调用你要用的函数就可以了.由于有写时拷贝的存在,这样做效率的损失应该也不大.
期待真正的高手的回答!
|
一个程序调用fork函数,系统为一个新的进程准备了数据段,堆栈段,代码段,
首先,新进程与旧进程使用同一个代码段,因为它们的程序是相同的,
对于数据段和堆栈段,系统则复制一份给新的进程,
这样,父进程的所有数据都可以留给子进程,但是,子进程一旦开始运行,
虽然它继承了父进程的一切数据,但实际上数据却已经分开,
相互之间不再有影响了,也就是说,它们之间不再共享任何数据了。
两个进程要共享数据的话,只能使用共享内存与消息队列等来操作。
如果数据段和堆栈都很大,一次fork就要复制一次,那么fork的开销岂不是很大?
其实一般CPU都是以“页”为单位分配空间的,
fork函数复制这两个段,只是“逻辑”上的,并非“物理”上的,也就是说,
实际执行fork时,物理空间上两个进程的绝大部分数据段和堆栈段都还是共享着的,
只有一个进程写了某个数据时,这时两个进程之间的数据才有了区别,
系统只将有区别的“页”从物理上也分开。系统在空间上的开销就可以达到最小。
要方便的使用共享变量,最好使用线程方式,但是需要考虑变量的保护问题,而
使用进程的共享内存与消息队列,就不需要用户来保护变量,因为它们已经提供了
保护。
首先,新进程与旧进程使用同一个代码段,因为它们的程序是相同的,
对于数据段和堆栈段,系统则复制一份给新的进程,
这样,父进程的所有数据都可以留给子进程,但是,子进程一旦开始运行,
虽然它继承了父进程的一切数据,但实际上数据却已经分开,
相互之间不再有影响了,也就是说,它们之间不再共享任何数据了。
两个进程要共享数据的话,只能使用共享内存与消息队列等来操作。
如果数据段和堆栈都很大,一次fork就要复制一次,那么fork的开销岂不是很大?
其实一般CPU都是以“页”为单位分配空间的,
fork函数复制这两个段,只是“逻辑”上的,并非“物理”上的,也就是说,
实际执行fork时,物理空间上两个进程的绝大部分数据段和堆栈段都还是共享着的,
只有一个进程写了某个数据时,这时两个进程之间的数据才有了区别,
系统只将有区别的“页”从物理上也分开。系统在空间上的开销就可以达到最小。
要方便的使用共享变量,最好使用线程方式,但是需要考虑变量的保护问题,而
使用进程的共享内存与消息队列,就不需要用户来保护变量,因为它们已经提供了
保护。
|
前段时间写程序,就犯了这个错误。误认为fork{}中可以改变fork外的数据,哈哈。
后来改成了内存影射,觉得麻烦,多线程就应该能解决我的问题,而且调度的效率也高,就改成
了多线程。