实验很快搞定了,学到了不少东西,当时我知道Unix编程不是这么几个简单的实验,但是已经对我来说不是那么陌生,突然发现Unix下的编程是十分简洁高效的!当然也因为不用考虑图形界面的设计,摆脱了不少看似简单但是十分麻烦的问题。但是这次主要是用c编程,而且实验实在太小了,也没用上啥面向对象思想,纯属玩弄c语言技巧了。当然也验证了一句话:“当你对c的经验增加时,她会显得十分的好用。”
(一)创建进程
fork()函数。使用简单明了,书上已经说了很多了。但是课本上的使用方法太没章法了,首先他定义pid用的是int,这是没什么问题,但是很不直观,不然用pid_t直观。其次,他对进程创建失败的处理可以说就没有,而且创建多个进程就多层嵌套了,很容易出错,这里也不贴这种不易维护的代码了,先看看我是如何练习这一项的。代码节选如下:
1
fprintf(stderr,
"
Proccess Begin.pid=[%d],i=[%d]\n
"
,getpid(),i);
2
if
((pid
=
fork())
>
0
){
3
fprintf(stderr,
"
Parent pid=[%d],child pid=[%d]\n
"
,getpid(),pid);
4
}
5
else
if
(pid
==
0
)
6
{
7
fprintf(stderr,
"
Child pid=[%d]\n
"
,getpid());
8
i
++
;
9
}
10
else
fprintf(stderr,
"
Fork failed.\n
"
);
11
fprintf(stderr,
"
Proccess end. pid=[%d]\n
"
,getpid(),i);
这段代码只是创建了一个进程的,同时将进程的pid打印到屏幕。
(二) 两个进程
两个进程的创建和一个创建没啥区别,这里引出一下,多个进程执行会发现进程调度。代码如下:
1
pid_t pid1,pid2;
2
int
status;
3
if
((pid1
=
fork())
<
0
) exit(
1
);
4
else
if
(pid1
==
0
)
/*
child Process 1
*/
5
{
6
signal(SIGINT,childfunc1);
7
printf(
"
I'm Child One!\n
"
);
8
sleep(
30
);
9
exit(
0
);
10
}
11
if
((pid2
=
fork())
<
0
)exit(
1
);
12
else
if
(pid2
==
0
)
/*
child Proccess 2
*/
13
{
14
signal(SIGINT,childfunc2);
15
printf(
"
I'm Child Two!\n
"
);
16
sleep(
30
);
17
exit(
0
);
18
}
19
20
fprintf(stderr,
"
Fork child pid=[%d][%d]\n
"
,pid1,pid2);
21
sleep(
1
);
22
getchar();
23
/*
printf("I'm Father!\n");
*/
24
kill(pid1,SIGINT);
25
wait(
&
status);
26
kill(pid2,SIGINT);
27
wait(
&
status);
28
fprintf(stderr,
"
Parent Process is Killed!\n
"
);
这里有了新的内容,主要就是下章要讲的了。
(三)信号
信号可以十分方便的控制进程,尤其是杀死他的时候……关于信号的种类十分多,不能在这一一阐述。这里使用的SIGINT信号,用于捕获中断信号,十分简单一个信号,对ctrl+c和del键有效,其中signal的使用方法请查看相关书籍。这里简略说一下kill的使用,杀进程主要靠 的就是他啦,发送信号就是了,然后wait是未来等待kill执行结束的。
(四)管道
管道这节小实验要求十分少,就是写入管道然后读出再输出到屏幕就行了……也没有要求双向通信,双向通信就要建两个管道
这里主要就演示一下写入和读取就是了。毕竟只是简单的函数调用,两个子进程分别写入数据,然后主进程再读取输出。代码如下:
else
if
(pid2
==
0
)
/*
child Proccess 2
*/
{
close(fildes[
0
]);
write(fildes[
1
],
"
Child 2 is sending a message!\n
"
,strlen(
"
Child 2 is sending a message!\n
"
));
return
;
}
close(fildes[
1
]);
memset(buf,
0
,
sizeof
(buf));
j
=
read(fildes[
0
],buf,
sizeof
(buf));
fprintf(stderr,
"
Message:\n%s Length:%d\n
"
,buf,j);
注意这里读取的方法,以及要清空缓存。
(五)总结
Unix下的编程一个词:简练,但是并不简单,这里所列出的仅限于实验有很大的局限性,连冰山一角都难算上。最后附上老师的附加实验的代码,不再讲解,签名能看懂的应该都差不多这个:
消息队列实验完全代码:
Code
1 #include <sys/msg.h>
2 #include <sys/types.h>
3 #include <sys/ipc.h>
4 #include <sys/errno.h>
5 #include <stdio.h>
6
7 extern int errno;
8 struct mymsgbuf
9 {
10 long mtype;
11 char ctext[100];
12 };
13 int main()
14 {
15 pid_t pid1,pid2;
16
17
18 if((pid2=fork())<0) exit(1);
19 else if (pid2==0) /* child Process server*/
20 {
21 int msgid,ret;
22 struct mymsgbuf buf;
23 if((msgid=msgget(0x004b,0666|IPC_CREAT))<0)
24 {
25 fprintf(stderr,"Open msg %X failed.\n",0x004b);
26 return;
27 }
28 while(buf.mtype!=1)
29 {
30 memset(&buf,0,sizeof(buf));
31 while((ret=msgrcv(msgid,&buf,sizeof(buf.ctext),0,0))<0)
32 {
33 if(errno==EINTR) continue;
34 return;
35 }
36 fprintf(stderr,"Msg: Type =%d,Len=%d,Text=%s \n",buf.mtype,ret,buf.ctext);
37 }
38 exit(0);
39 }
40
41 if((pid1=fork())<0)
42 {
43 fprintf(stderr,"fork error!\n");
44 return;
45 }
46 else if(pid1==0) /*child Proccess chient*/
47 {
48
49 int msgid2,i;
50 struct mymsgbuf sbuf;
51 if((msgid2=msgget(0x004b,0666|IPC_CREAT))<0)
52 {
53 fprintf(stderr,"Open msg %X failed.\n",0x004b);
54 return;
55 }
56 memset(&sbuf,0,sizeof(sbuf));
57 for(i=10;i>=1;i--)
58 {
59 sbuf.mtype=i;
60 sprintf(sbuf.ctext,"%d (client)sent\n",i);
61 for(;(msgsnd(msgid2,&sbuf,strlen(sbuf.ctext),0))<0;)
62 {
63 if(errno==EINTR) continue;
64 return;
65 }
66 }
67 exit(0);
68 }
69
70
71 fprintf(stderr,"Fork child pid=[%d][%d]\n",pid1,pid2);
72
73
74
75 }
希望您能从这里有所收获,本blog未经特殊说明均为原创,转载请注明出处,谢谢合作!