进程
来源:互联网 发布:mysql 存储过程 参数 编辑:程序博客网 时间:2024/04/30 19:32
一.进程
1.什么是进程
定义:一个其中运行着一个或者多个线程的地址空间和这些线程所需要的系统资源
2.进程的结构
如果有两个用户neil和rick,他们同时运行grep程序在不同的文件中查找不同的字符串。
如果在搜索结束之前运行ps -ef 命令,则出现以下内容。
$ps -ef
UID PID PPID C STIME TTY TIME CMD
rick 101 96 0 18:24 tty2 00:00:00 grep tr n.txt
neil 102 92 0 18:24 tty4 00:00:00 grep hr u.txt
结论:
- 每一个进程都会被分配唯一的一个数字编号,叫进程标识符或者PID。他通常取值为2到32768的正整数。1为特殊进程init
- 将要被grep执行的程序代码被保存在一个磁盘文件中,正常情况下,linux进程不能对用来存放程序代码的内存区域进行写操作,即程序代码是以只读方式加载到内存中去的。可以被多个进程安全的共享。
- 系统函数库也可以被共享。例如,不管有多少个运行的程序要调用printf函数,内存中只要有它的一个副本即可。
- 进程有自己的栈空间,用于保存局部变量和控制函数的调用和返回。
- 进程有自己的环境空间用于保存自己的环境变量。
- 进程还必须保存自己的程序计数器,用于保存执行的位置。
1 ? Ss 0:01 /sbin/init
2 ? S 0:00 [kthreadd]
3 ? S 0:00 [migration/0]
4 ? S 0:00 [ksoftirqd/0]
5 ? S 0:00 [migration/0]
6 ? S 0:00 [watchdog/0]
7 ? S 0:00 [events/0]
8 ? S 0:00 [cgroup]
9 ? S 0:00 [khelper]
10 ? S 0:00 [netns]
11 ? S 0:00 [async/mgr]
12 ? S 0:00 [pm]
13 ? S 0:00 [sync_supers]
14 ? S 0:00 [bdi-default]
15 ? S 0:00 [kintegrityd/0]
16 ? S 0:00 [kblockd/0]
17 ? S 0:00 [kacpid]
18 ? S 0:00 [kacpi_notify]
19 ? S 0:00 [kacpi_hotplug]
20 ? S 0:00 [ata/0]
21 ? S 0:00 [ata_aux]
22 ? S 0:00 [ksuspend_usbd]
23 ? S 0:00 [khubd]
24 ? S 0:00 [kseriod]
25 ? S 0:00 [md/0]
26 ? S 0:00 [md_misc/0]
27 ? S 0:00 [khungtaskd]
28 ? S 0:00 [kswapd0]
29 ? SN 0:00 [ksmd]
30 ? S 0:00 [aio/0]
31 ? S 0:00 [crypto/0]
36 ? S 0:00 [kthrotld/0]
37 ? S 0:00 [pciehpd]
39 ? S 0:00 [kpsmoused]
40 ? S 0:00 [usbhid_resumer]
70 ? S 0:00 [kstriped]
327 ? S 0:00 [mpt_poll_0]
328 ? S 0:00 [mpt/0]
329 ? S 0:00 [scsi_eh_0]
335 ? S 0:00 [scsi_eh_1]
336 ? S 0:00 [scsi_eh_2]
346 ? S 0:00 [scsi_eh_3]
347 ? S 0:01 [scsi_eh_4]
348 ? S 0:00 [scsi_eh_5]
349 ? S 0:00 [scsi_eh_6]
350 ? S 0:00 [scsi_eh_7]
351 ? S 0:00 [scsi_eh_8]
352 ? S 0:00 [scsi_eh_9]
353 ? S 0:00 [scsi_eh_10]
354 ? S 0:00 [scsi_eh_11]
355 ? S 0:00 [scsi_eh_12]
356 ? S 0:00 [scsi_eh_13]
357 ? S 0:00 [scsi_eh_14]
358 ? S 0:00 [scsi_eh_15]
359 ? S 0:00 [scsi_eh_16]
360 ? S 0:00 [scsi_eh_17]
361 ? S 0:00 [scsi_eh_18]
362 ? S 0:00 [scsi_eh_19]
363 ? S 0:00 [scsi_eh_20]
364 ? S 0:00 [scsi_eh_21]
365 ? S 0:00 [scsi_eh_22]
366 ? S 0:00 [scsi_eh_23]
367 ? S 0:00 [scsi_eh_24]
368 ? S 0:00 [scsi_eh_25]
369 ? S 0:00 [scsi_eh_26]
370 ? S 0:00 [scsi_eh_27]
371 ? S 0:00 [scsi_eh_28]
372 ? S 0:00 [scsi_eh_29]
373 ? S 0:00 [scsi_eh_30]
374 ? S 0:00 [scsi_eh_31]
375 ? S 0:00 [scsi_eh_32]
492 ? S 0:01 [jbd2/sda2-8]
493 ? S 0:00 [ext4-dio-unwrit]
515 ? S 0:00 [flush-8:0]
580 ? S<s 0:00 /sbin/udevd -d
778 ? S 0:00 [vmmemctl]
1071 ? S 0:00 [bluetooth]
1144 ? S< 0:00 /sbin/udevd -d
1145 ? S< 0:00 /sbin/udevd -d
1188 ? S 0:00 [jbd2/sda1-8]
1189 ? S 0:00 [ext4-dio-unwrit]
1240 ? S 0:00 [kauditd]
1488 ? Ssl 0:00 /usr/sbin/vmware-vmblock-fuse -o subtype=vmware-vmblo
1521 ? Sl 0:06 /usr/sbin/vmtoolsd
1726 ? Sl 0:00 /sbin/rsyslogd -i /var/run/syslogd.pid -c 5
1768 ? Ss 0:00 rpcbind
1783 ? Ssl 0:00 dbus-daemon --system
1794 ? Ss 0:00 NetworkManager --pid-file=/var/run/NetworkManager/Net
1800 ? S 0:00 /usr/sbin/modem-manager
1806 ? S 0:00 avahi-daemon: running [linux.local]
1807 ? Ss 0:00 avahi-daemon: chroot helper
1810 ? Ss 0:00 /usr/sbin/wpa_supplicant -c /etc/wpa_supplicant/wpa_s
1827 ? Ss 0:00 rpc.statd
1861 ? S 0:00 [rpciod/0]
1865 ? Ss 0:00 rpc.idmapd
1875 ? Ss 0:00 cupsd -C /etc/cups/cupsd.conf
1900 ? Ss 0:00 /usr/sbin/acpid
1909 ? Ss 0:00 hald
1910 ? S 0:00 hald-runner
1940 ? S 0:00 /usr/libexec/hald-addon-rfkill-killswitch
1951 ? S 0:00 hald-addon-input: Listening on /dev/input/event2 /dev
1957 ? S 0:00 hald-addon-acpi: listening on acpid socket /var/run/a
1976 ? Ssl 0:00 automount --pid-file /var/run/autofs.pid
1994 ? S<s 0:00 /usr/sbin/bluetoothd --udev
2005 ? Ss 0:00 /usr/sbin/sshd
2098 ? Ss 0:00 tpvmlpd2
2118 ? S< 0:00 [krfcommd]
2255 ? Ss 0:00 /usr/libexec/postfix/master
2262 ? S 0:00 pickup -l -t fifo -u
2263 ? S 0:00 qmgr -l -t fifo -u
2279 ? Ss 0:00 /usr/sbin/abrtd
2287 ? Ss 0:00 abrt-dump-oops -d /var/spool/abrt -rwx /var/log/messa
2295 ? Ss 0:00 crond
2311 ? Ss 0:00 /usr/sbin/atd
2326 ? Ss 0:00 /usr/bin/rhsmcertd 240 1440
2342 ? Ss 0:00 /usr/sbin/certmonger -S -p /var/run/certmonger.pid
2349 ? Ss 0:00 /usr/sbin/gdm-binary -nodaemon
2354 tty2 Ss+ 0:00 /sbin/mingetty /dev/tty2
2356 tty3 Ss+ 0:00 /sbin/mingetty /dev/tty3
2358 tty4 Ss+ 0:00 /sbin/mingetty /dev/tty4
2360 tty5 Ss+ 0:00 /sbin/mingetty /dev/tty5
2364 tty6 Ss+ 0:00 /sbin/mingetty /dev/tty6
2377 ? S 0:00 /usr/libexec/gdm-simple-slave --display-id /org/gnome
2379 tty1 Ss+ 0:09 /usr/bin/Xorg :0 -nr -verbose -audit 4 -auth /var/run
2395 ? Sl 0:00 /usr/sbin/console-kit-daemon --no-daemon
2465 ? S 0:00 /usr/bin/dbus-launch --exit-with-session
2471 ? S 0:00 /usr/libexec/devkit-power-daemon
2515 ? S 0:00 /usr/libexec/polkit-1/polkitd
2522 ? SNl 0:00 /usr/libexec/rtkit-daemon
2528 ? S 0:00 pam: gdm-password
2611 ? Sl 0:00 /usr/bin/gnome-keyring-daemon --daemonize --login
2620 ? Ssl 0:00 gnome-session
2628 ? S 0:00 dbus-launch --sh-syntax --exit-with-session
2629 ? Ssl 0:00 /bin/dbus-daemon --fork --print-pid 5 --print-address
2657 ? S 0:00 /usr/libexec/gconfd-2
2666 ? Ssl 0:00 /usr/libexec/gnome-settings-daemon
2673 ? Ss 0:00 seahorse-daemon
2676 ? S 0:00 /usr/libexec/gvfsd
2684 ? Sl 0:00 metacity
2693 ? S<sl 0:02 /usr/bin/pulseaudio --start --log-target=syslog
2694 ? S 0:00 gnome-panel
2701 ? S 0:00 /usr/libexec/pulse/gconf-helper
2702 ? S 0:08 nautilus
2704 ? Ssl 0:00 /usr/libexec/bonobo-activation-server --ac-activate -
2712 ? S 0:00 /usr/libexec/wnck-applet --oaf-activate-iid=OAFIID:GN
2713 ? S 0:00 /usr/libexec/trashapplet --oaf-activate-iid=OAFIID:GN
2715 ? S 0:00 /usr/libexec/gvfs-gdu-volume-monitor
2717 ? S 0:00 /usr/libexec/udisks-daemon
2719 ? S 0:00 /usr/libexec/gvfsd-trash --spawner :1.7 /org/gtk/gvfs
2720 ? S 0:01 udisks-daemon: polling /dev/sr0
2723 ? S 0:00 /usr/libexec/gdu-notification-daemon
2724 ? Sl 0:13 /usr/lib/vmware-tools/sbin32/vmtoolsd -n vmusr --bloc
2725 ? S 0:00 gpk-update-icon
2729 ? S 0:00 gnome-volume-control-applet
2730 ? S 0:00 nm-applet --sm-disable
2731 ? S 0:00 gnome-power-manager
2735 ? S 0:00 bluetooth-applet
2737 ? S 0:00 rhsm-icon
2745 ? S 0:00 abrt-applet
2749 ? S 0:00 /usr/libexec/im-settings-daemon
2750 ? S 0:00 /usr/sbin/restorecond -u
2752 ? S 0:00 python /usr/share/system-config-printer/applet.py
2758 ? S 0:00 /usr/libexec/polkit-gnome-authentication-agent-1
2764 ? S 0:00 /usr/libexec/gvfs-gphoto2-volume-monitor
2772 ? Sl 0:00 /usr/libexec/gvfs-afc-volume-monitor
2948 ? S 0:00 /usr/libexec/notification-daemon
2955 ? Sl 0:00 /usr/bin/ibus-daemon -r --xim
2958 ? S 0:00 /usr/libexec/gconf-im-settings-daemon
2959 ? Ss 0:03 gnome-screensaver
2968 ? S 0:00 /usr/bin/gnote --panel-applet --oaf-activate-iid=OAFI
2969 ? S 0:00 /usr/libexec/clock-applet --oaf-activate-iid=OAFIID:G
2970 ? S 0:00 /usr/libexec/gdm-user-switch-applet --oaf-activate-ii
2971 ? S 0:00 /usr/libexec/notification-area-applet --oaf-activate-
2977 ? S 0:00 /usr/libexec/ibus-gconf
2979 ? S 0:00 python /usr/share/ibus/ui/gtk/main.py
2981 ? S 0:00 /usr/libexec/ibus-x11 --kill-daemon
2982 ? S 0:00 /usr/libexec/ibus-engine-pinyin --ibus
3024 ? S 0:00 /usr/libexec/gvfsd-burn --spawner :1.7 /org/gtk/gvfs/
3027 ? S 0:00 /usr/libexec/gvfsd-metadata
3063 ? Sl 0:02 gnome-terminal
3064 ? S 0:00 gnome-pty-helper
3065 pts/0 Ss 0:00 bash
3228 ? Ss 0:00 /usr/sbin/anacron -s
3617 ? S 0:00 /usr/libexec/fprintd
3625 pts/0 R+ 0:00 ps ax
- R+表示程序已经准备好运行,并不意味着它正在运行。所以只能表示这是一个前台任务。
- 时间片概念
- 表现良好的程序称为nice程序。在多任务系统中,多个进程可能竞争同一个资源。在这种情况下,执行短期的突发性工作并暂停运行等待输入的程序,要比持续占用处理器来进行计算或者不断轮询系统来查看是否有心得输入到达的程序要更好。
- 系统会根据nice值来决定它的优先级
- nice命令设置进程的优先级,renice命令调整它的值。nice命令将他的nice值增加10,从而降低它的nice值。(NI为nice 值)
0 S 500 3065 3063 0 80 0 - 1310 - pts/0 00:00:00 bash
0 R 500 4168 3065 5 80 0 - 1215 - pts/0 00:00:00 ps
- 其中STAT中N字符表明这个进程的nice已经被修改了
- 如果父进程已经不存在,则父进程为1(init)
int system(const char *command);
- system函数的作用是:运行以字符串形式创递给它的命令等待该命令的完成。命令的执行情况就如同在shell中执行如下命令。
- sysrem的返回值:如果无法启动shell执行这个命令,system函数返回错误代码127;如果是其他错误,则返回-1;否则,system函数将返回该命令的退出码。
- 用system 编写一个程序,让它替我们运行ps程序。
#include<stdlib.h>#include<stdio.h>int main(){printf("Running ps with system\n");system("ps ax");printf("Done.\n");exit(0);}$./system1
Running ps with systemPID TTY STAT TIME COMMAND1 ? Ss 0:02 /sbin/init2 ? S 0:00 [kthreadd]........
3261 ? S 0:00 /usr/sbin/packagekitd
3274 pts/0 S+ 0:00 ./system1
3275 pts/0 R+ 0:00 ps ax
Done.
修改程序为system("ps ax &")
$./system1
Running ps with system
Done.
[hui@localhost 517]$ PID TTY STAT TIME COMMAND
1 ? Ss 0:02 /sbin/init
2 ? S 0:00 [kthreadd]......
3137 ? S 0:00 /usr/libexec/notification-daemon
3329 pts/0 R 0:00 ps ax实验分析:"ps ax "为参数时,system函数在执行完ps命令后返回。必须由system启动的进程结束后才能继续,不能执行其他任务。
"pa ax &"为参数时,ps程序一启动它就返回了。
- system对shell的依赖性很大,效率不高。
int execve(const char *filename, char *const argv[],
- exec系列函数由一组相关的函数组成。
- exec函数可以把当前进程替换为一个新进程,新进程由path函数和file参数制定。
- exec函数比system函数更有效,在心得程序启动后,就不用运行原来的程序了。
- #include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,
..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);char *const envp[]);
- 函数分为两大类,execl,execlp,execle是可变参的,参数以一个空指针结束。 execv execvp的第二个参数是字符串数组。新程序启动时会把argv数组中给定的参数传递给main函数。
- 这些函数通常都是由execve实现的,虽然没有必要这样做。
- 以字母p结尾的函数通过PATH环境变量来查找新程序可执行文件的路径。如果可执行文件的路径不在PATH定义的路径中,我们就需要在包括目录在内的绝对路径的文件名作为参数传递给函数。
- 试验程序
#include<unistd.h>
#include<stdlib.h>#include<stdio.h>char *const ps_argv[] = {"ps","ax",0};char *const ps_envp[] = {"PATH=/bin:/usr/bin","TERM=console",0};int main(){printf("Running pa with exec\n");//execl("/bin/ps","ps","ax",0);execlp("ps","ps","ax",0);//execle("/bin/ps","ps","ax",ps_envp);//execv("/bin/ps",ps_argv);//execvp("ps",ps_argv);//execve("/bin/ps",ps_argv,ps_envp);exit(0);}
一般情况下,exec函数是不会反回的,除非发生了错误。出现错误时,exec函数返回-1,并且设置错误变量errno。
由exec启动的新程序继承了原来的程序的多样性,特别的,在原进程打开的文件描述符在新进程中任然保持打开,除非他们的"执行关闭标志(close on exec flag)被设置"(fcntl系统调用)。任何在原程序目标流都将在新程序中关闭。
3.2 复制进程映像
要想要一个进程同时执行多个函数,可以用线程或者从原程序中创建一个分离的进程,后者就像init一样,而不像exec调用那样用新的程序替换当前执行的线程。
fork创建一个新进程:这个系统调用复制当前进程,在进程表中创建一个新的表项,新表项中有许多属性都和当前进程一模一样,执行的代码也完全相同,但新进程有自己的数据空间、环境和文件描述符。
#include <unistd.h>
pid_t fork(void);
父进程返回子进程的PID,子进程返回0;
2.1等待一个进程
我们希望知道子进程在何时结束。可以在父进程中调用wait函数等待子进程的结束。
#include <sys/wait.h>
pid_t wait(int *stat_loc);
wait系统代用将暂停父进程知道子进程结束为止,这个调用返回子进程的PID,stat_loc指向子进程的退出码。
2.2僵尸进程
子进程终止时,他与父进程之间的还会保持联系,直到父进程也正常终止或者父进程盗用wait才结束。
因此代表子进程的表项不会立刻释放,虽然子进程已经结束,但它仍然存在于系统中,,因为它的退出码还需要保存起来,以备以后的父进程wait调用使用。此时他将会成为一个僵(zombie)尸进程或者死(defunct)进程。
实例
父进程先结束:
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
int main()
{
char *message;
int n;
int exit_code;
printf("forring\n");
pid_t pid = fork();
switch(pid)
{
case -1:
perror("fork failed");
exit(1);
case 0:
message = "child";
n = 5;
exit_code = 100;
break;
default:
message = "father";
n = 3;
exit_code = 50;
break;
}
while(n)
{
puts(message);
--n;
}
if(pid != 0)
{
int stat_val;
pid_t childpid = wait(&stat_val);
printf("child( PID = %d ) finished\n",childpid);
if(WIFEXITED(stat_val))
{
printf("child exited with code %d\n",WEXITSTATUS(stat_val));
}
else
{
printf("child terminated abnormally\n");
}
}
exit(exit_code);
}
$ gcc -o fork1 fork1.c
$ ./fork1
forring
father
child
father
child
father
child
child
child
child( PID = 3342 ) finished
child exited with code 100
子进程先结束:
#include<stdio.h>
3.3输入输出重定向#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
int main()
{
char *message;
int n;
int exit_code;
printf("forring\n");
pid_t pid = fork();
switch(pid)
{
case -1:
perror("fork failed");
exit(1);
case 0:
message = "child";
n = 5;
exit_code = 100;
break;
default:
message = "father";
n = 3;
exit_code = 50;
break;
}
while(n)
{
puts(message);
--n;
}
if(pid != 0)
{
int stat_val;
pid_t childpid = wait(&stat_val);
printf("child( PID = %d ) finished\n",childpid);
if(WIFEXITED(stat_val))
{
printf("child exited with code %d\n",WEXITSTATUS(stat_val));
}
else
{
printf("child terminated abnormally\n");
}
}
exit(exit_code);
}
$./fork2
forring
father
child
father
child
father
child
father
father
child( PID = 3473 ) finished
child exited with code 100$ ps -al(在子进程结束以后父进程未结束时ps)
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 500 3472 2982 0 80 0 - 462 - pts/0 00:00:00 fork2
1 Z 500 3473 3472 0 80 0 - 0 ? pts/0 00:00:00 fork <defunct>
0 R 500 3475 3256 0 80 0 - 1215 - pts/1 00:00:00 ps
- 如果此时父进程异常终止,子进程将由init接管,子进程将是一个不在运行的僵尸进程,僵尸进程将一直保留在进程表中直到被init发现并释放。
- 进程表越大,init发现就越慢。在init发现他们之前,一直占用系统资源
#include <sys/types.h>
#include <sys/wait>
pid_t waitpid(pid_t pid, int *status, int options);实验upper.c
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
int main()
{
int ch;
while((ch = getchar()) != EOF)
{
putchar(toupper(ch));
}
exit(0);
}
$ ./upper
hello world
HELLO WORLD
$ ./upper < upper.c
#INCLUDE<STDIO.H>
#INCLUDE<STDLIB.H>
#INCLUDE<CTYPE.H>
INT MAIN()
{
INT CH;
WHILE((CH = GETCHAR()) != EOF)
{
PUTCHAR(TOUPPER(CH));
}
EXIT(0);
}