各位好以下是我来验证子进程与父进程之间不共享数据的代码
1 #include<unistd.h>
2 #include<stdio.h>
3 #include<stdlib.h>
4 int x = 9;
5 int main(int args, char *argc[])
6 {
7 int status;
8 while(1)
9 {
10 if(fork() != 0)//father process
11 {
12 x++;
13 waitpid( -1, &status, 0 );
14 printf("father's x is %d\n", x);
15 printf("father's x is address %o\n", &x);
16 exit(0);
17 }
18 else //son processes
19 {
20 x--;
21 printf("son's x is %d\n", x);
22 printf("son's x is address %o\n", &x);
23 exit(0);
24 }
25 }
26 return 0;
27 }
在shell中执行该文件编译后的默认程序 a.out 后结果输出如下:
[root@localhost test]# ./a.out
son's x is 8
son's x is address 1001113660
father's x is 10
father's x is address 1001113660
[root@localhost test]#
问题来了,,,我能理解父进程与子进程的全局变量 x 的不同,但是对他们的 x 的地址却相同是什么原因啊?是不是他们的虚拟地址相同,但对应的物理地址不同啊?????各位大侠来帮小弟理解下啊!!!
引用 4 楼 的回复:
引用 1 楼 的回复:因为子进程的地址空间完全是从父进程复制过来的(copy on write),所以x的地址相同是正常的
但是虽然父子进程的x地址相同,但不并是同一个变量,因为fork过后父子进程的进程空间是相互独立的,不会相互影响.
感觉还是很矛盾,既然两个进程空间是互相独立的,但是地址是一样的,那么就指向同一个空间。除非就像楼主说的一样,这是虚拟地址,虚拟地址可以一样……
你理解的差不多了,那个一样的地址是线性地址,每个进程的相同的线性地址都可以映射到不同的物理地址上。在fork的时候,子进程从父进程了copy了task_struct结构,其中task_struct里的mm就是线性地址的使用情况,mm也会被copy给子进程,所以在fork之前声明的变量,在fork后在父进程和子进程里的线性地址是一样的。
http://bbs.csdn.net/topics/390223958
题目:
我执行了这些语句:
CREATE OR REPLACE TYPE plch_numbers_nt IS TABLE OF NUMBER; / CREATE OR REPLACE TYPE plch_numbers_vat IS VARRAY (10) OF NUMBER; / CREATE OR REPLACE PACKAGE plch_pkg IS TYPE plch_numbers_nt IS TABLE OF NUMBER; END; / CREATE OR REPLACE TYPE plch_numbers_aat IS TABLE OF NUMBER INDEX BY PLS_INTEGER; /
然后我写了如下的不完整代码块:
DECLARE l_count PLS_INTEGER; l_numbers /*TYPE*/ := /*TYPE*/ (1, 2, 3, 4, 5); BEGIN SELECT COUNT (COLUMN_VALUE) INTO l_count FROM TABLE (l_numbers); DBMS_OUTPUT.put_line (l_count); END; /
哪些选项可用来取代 /*TYPE*/ 注释,从而使得代码块执行之后会显示"5"?
(A) plch_numbers_nt (B) plch_numbers_vat (C) plch_pkg.plch_numbers_nt (D) plch_numbers_aat
答案:
A: plch_numbers_nt是在SCHEMA级别定义的嵌套表类型(NESTED TABLE)所以可被SQL引擎识别并用TABLE()函数转换为表
B: plch_numbers_vat是在SCHEMA级别定义的可变数组类型(VARRAY)所以可被SQL引擎识别并用TABLE()函数转换为表
C: plch_pkg.plch_numbers_nt是在包级别定义的,无法被SQL引擎识别
D: 关联数组只能在PLSQL中使用,实际上plch_numbers_aat不能成功创建,会报错:
SQL> CREATE OR REPLACE TYPE plch_numbers_aat IS TABLE OF NUMBER 2 INDEX BY PLS_INTEGER; 3 / Warning: Type created with compilation errors. Elapsed: 00:00:04.76 SQL> SHOW ERR Errors for TYPE PLCH_NUMBERS_AAT: LINE/COL ERROR -------- ----------------------------------------------------------------- 0/0 PL/SQL: Compilation unit analysis terminated 1/26 PLS-00355: use of pl/sql table not allowed in this context
起因:
做的项目,三层架构:domain层(dao)、façade层(business)、view层。View层用Extjs实现,使用SSH组合,在façade层配置了REQUIRED型事务,在domain层没有采用默认事务。按说,在façade层配置了事务之后,同一次操作(同一个façade方法)对domain层的调用一定应该是同一事务,这个由spring保证的。但领导怀疑看到有不一致的数据,怀疑是由于同一次操作没有在同一事务中(应该是系统开发过程中不完善造成的),让验证一下同一次façade层的操作,对domain层是不是在同一个事务中。
验证方法有两种:
1. 在一次façade层的方法入口处获取事务,保存,然后在调用相关的domain层方法中手动添加获取事务,验证和入口处的事务是不是同一事务。这种方案需要先在各相关方法中添加代码,验证完成后,再把新加的代码清除,工作量大,而且易出错。
2. 通过spring的aop功能,生成切面,在每个facade方法调用的domain方法前或后得到事务,验证同一次操作对domain层的方法是否在同一事务中。
鉴于第二种方法只需要独立生成一个新切面类,并修改配置方法就可以完成,而且可以借此机会学习一下spring的aop,所以决定采用第二种方案。
首先实现一个切面类:
public class MyAspect { public void doAfter(JoinPoint jp){ System.out.println("log Ending method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName()); } public void doBefore(JoinPoint jp) { System.out.println("log Begining method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName()); } }
然后修改spring配置文件beans.xml,添加如下内容:
<!--切面实现1 Begin --> <aop:config> <aop:pointcut id="myAspectAA" expression="execution(* com.dfsoft.hummer.domain..*Impl.add*(..)) or execution(* com.dfsoft.hummer.domain..*Impl.del*(..)) or execution(* com.dfsoft.hummer.domain..*Impl.save*(..))"/> <aop:aspect id="myAspect" ref="myAspect1"> <aop:before pointcut-ref="myAspectAA" method="doBefore"/> <aop:after pointcut-ref="myAspectAA" method="doAfter"/> </aop:aspect> </aop:config> <bean id="myAspect1" class="com.dfsoft.hummer.domain.common.MyAspect" /> <!-- 切面实现1 End-->
运行程序,进行相关操作,查看结果,看到切面成功执行。
验证同一façade方法对domain的调用是否在同一事务,只需要使用before或after一个就行,我这里使用了before。修改before方法如下:
public void doBefore(JoinPoint jp) { System.out.println(); try{ Method m = jp.getTarget().getClass().getDeclaredMethod("getSession"); //反射 m.setAccessible(true); //使私有方法可操作 Session s = (Session)m.invoke(jp.getTarget()); System.out.println(s.getTransaction().hashCode()); }catch(Exception e){ System.out.println("No such method: " + e.getMessage()); } System.out.println("log Begining method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName()); }
再一次运行程序,进行相关操作,查看控制台,看到同一次操作输入的事务的hashcode是同一个,这就可以认为同一次façade方法调用,所有的domain调用是在同一事务中。
验证完成后,删除MyAspect类,清除配置文件中修改,就完成了还原的工作。
本来一个功能是应该写测试来保证后续的修改不会引入错误,但考虑到这个工作是一次性的,用完就清除了,所以就没有写测试。