Linux C 编程之进程

时间:2021-03-05 14:53:56

本来上学期应该好好看的东西,却拖到了现在,以后会坚持更新博客。废话不多说了,进入正题。

注:本文所说的都是在Linux 下,Windows底下的没有看过。

首先要说的就是程序进程的区别:

程序:是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。

进程:是程序在处理机上的一次执行过程,它是一个动态的概念。(摘自百度百科)

区分完了程序和进程的区别下面来重点讨论进程!~

1.进程描述符(pid)

操作系统给每个进程都分配了自己一个特有的pid,这个pid是唯一的,可重用的。每次新创建一个进程后,系统就会自动分配一个进程描述符(pid,非负整数,每次都是上一次创建进程的pid+1),pid的最大值是32767。在这里你可能会问那当一个程序一直加到32767后,后面创建的进程怎么办?这个不用担心,当前面的进程结束后,这些进程的pid你就可以继续使用了,这就是可重用性。其中pid=0的进程是调度进程,pid=1的进程是init进程,pid=2的是页守护进程。init进程不是内核中的系统进程,它是一个普通用户进程,只不过以root权限运行。在进程中每一个进程都由task_struct来定义,有兴趣的可以继续深入了解,这里就不再赘述。

task_struct结构体的详细解释:http://blog.csdn.net/jurrah/article/details/3965437

2.进程中的一些函数:

说到进程不能不说的就是fork()这个函数了,fork():创建一个进程,子进程获得了父进程数据空间,栈,和堆的副本。父子进程共享正文段。由于现在很多都是在fork ()之后,就运行exec ,所以就不执行父进程的数据段,栈,堆,所以就有了一个写时拷贝 (copy-on-write),这些区域就父子进程共享,内核对他们的设置的访问权限是只读。当父子进程其中有一个在试图修改这些区域的时候,内核只为修改的区域在内存中制左一个副本。(摘自陈露纹同学的讲义)

父子进程共享同一个文件描述符,共享同一个文件偏移量。

然后说说跟fork()有些相似的vfork():vfork()在调用exec之前和父进程共享数据,并且它保证子进程先执行,如果在调用exec和exit之前需要等待父进程的话将会导致死锁。最重要的一点:vfork()必须显式的调用exit()退出,否则其会出现不可预知的错误。

关于exec系函数我自己也没有理解多少,如果有哪位大神有好的博文的话可以让我看看。

然后就是僵尸进程和孤儿进程,我也只知道概念,有兴趣的话自己去百度上找找资料看看。

接下来就是wait()和waitpid()这两个函数了,对于两个函数的参数及返回值我就不再赘述了,大家都懂。进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。waitpid其实跟wait的功能差不多,只不过它可以等待特定的进程退出。

关于fork()之后是父进程先执行还是子进程先执行取决于操作系统的调度算法。

现在来举一些例子来说明一些问题。

	pid_t pid;
int i;

for(i=0; i<2; i++)
{
pid = fork();
printf("-");
}

大家猜一下这段代码会打印出几个'-'字符?具体解释详见: http://coolshell.cn/articles/7965.html

下面是我写的一个实现自己的简单的shell命令,写的很粗糙,各位凑合着看吧。。

/*
* =====================================================================================
*
* Filename: my_shell.c
*
* Description: realize my shell
*
* Version: 1.0
* Created: 2013å¹´07æ28æ¥ 22æ¶36å01ç§
* Revision: none
* Compiler: gcc
*
* Author: lvwei, xiyou.jike1101lw@gmail.com
* Company:
*
* =====================================================================================
*/

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <wait.h>

#define max_input 256
#define max_command 100
#define normal 0
#define out_redirect 1
#define in_redirect 2
#define have_pipe 4


//è¾å¥å­ç¬¦ä¸²å½ä»¤ï¼ä½¿å¶å­å¨buf中
void get_input(char *buf)
{
int i;
char ch;

ch = getchar();
for(i=0; i<max_input && ch!='\n' ; i++)
{
buf[i] = ch;
ch = getchar();
}
if(i == max_input)
{
printf("command is too long !\n");
exit(-1);
}
buf[i] = '\n';
i++;
buf[i] = '\0';
}

/* è¿åå½ä»¤ç个æ°ï¼buf为è¾å¥çå­ç¬¦ä¸²ï¼command为å½ä»¤è§£æåå­å¨çå°æ¹
*/
int explain_parameter(char *buf,char (*command)[max_input])
{
int count = 0;
int i,n;

for(i=0,n=0; buf[i] != '\n'; i++)
{
if(buf[i] == ' ')
{
command[count][n] = '\0';
count++;
n = 0;
continue;
}
command[count][n++] = buf[i];
}
command[count][n] = '\0';
return count+1;
}
/*对å½ä»¤çåæ°è¿è¡è§£æï¼ç®ååªæ¯æ带æä¸ä¸ª'<'æ'>'æ'|'
*/
int explain_command(char (*command)[max_input],int count_command,int background)
{
int i,number = 0;
int flag = 0;

for(i=0; i<count_command;i++)
{
if(command[i][0] == '&')
{
if(i == count_command-1)
{
background = 1;
strcpy(command[count_command-1],"\0");
break;
}
else
{
printf("wrong command!\n");
return -1;
}
}
if(command[i][0] == '>')
{
flag = flag | out_redirect;
number++;
if(command[i+1] == NULL)
{
number++;
}
}
if(command[i][0] == '<')
{
flag = flag | in_redirect;
number++;

if(command[i+1] == NULL)
{
number++;
}
}
if(command[i][0] == '|')
{
flag = flag | have_pipe;
number++;
if(command[i+1] == NULL)
{
number++;
}
if(i == 0)
{
number++;
}
}
if(number > 1) //ç®åè¿ä¸æ¯æå¤ä¸ª'>','<','|'符å·
{
printf("command wrong ! !!!!\n");
return -1;
}
}
return flag;
}

//æ¥æ¾å½ä»¤æ¯å¦å¯ä»¥è¢«æ¾å°
int find_command(char *command)
{
DIR *dp;
struct dirent *dirp;
char *path[] = { "./" , "/bin" , "/usr/bin/" , "NULL"};
int i;

if(strncmp(command,"./",2) == 0)
{
command = command + 2;
}

for(i = 0; path[i] != NULL ; i++)
{
if( (dp = opendir(path[i])) == NULL)
{
printf("cant open %s \n",path[i]);
continue;
}
while( (dirp = readdir(dp)) != NULL)
{
if(strcmp(command,dirp->d_name) == 0)
{
closedir(dp);
return 1;
}
}
closedir(dp);
}
return 0;
}

//æ§è¡è¿äºå½ä»¤
void exec_command(char *command[max_input],int flag,int background)
{
pid_t pid,pid2;
int status,status2;
char *filename,*pipe_next_command[max_command];
int i,j;
int fd,fd2;

for(i=0; command[i] != NULL ; i++)
{
if(flag == out_redirect || flag == in_redirect)
{
if(command[i][0] == '<' || command[i][0] == '>')
{
filename = command[i+1];
command[i] = NULL;
}
}
else if(flag == have_pipe)
{
if(command[i][0] == '|')
{
command[i] = NULL;
for(j=i+1; command[j] != NULL; j++)
{
pipe_next_command[j-i-1] = command[j];
}
pipe_next_command[j-i-1] = NULL;
break;
}
}
}

if((pid = fork()) < 0)
{
perror("fork");
return ;
}
switch(flag)
{
case normal :
if(pid == 0)
{
if( !find_command(command[0]) )
{
printf("%s : command not found \n",command[0]);
exit(0);
}
execvp(command[0],command);
exit(0);
}
break;
case out_redirect :
if(pid == 0)
{
if(!find_command(command[0]))
{
printf("%s : command not found \n",command[0]);
exit(0);
}
if((fd = open(filename,O_CREAT | O_RDWR | O_TRUNC,0644)) == 0)
{
printf("can't open file \n");
return ;
}
dup2(fd,1);
execvp(command[0],command);
exit(0);
}
break;
case in_redirect :
if(pid == 0)
{
if(!find_command(command[0]))
{
printf("%s : command not found \n",command[0]);
exit(0);
}
if((fd = open(filename,O_RDWR)) == 0)
{
printf("can't open file \n");
return ;
}
dup2(fd,0);
execvp(command[0],command);
exit(0);
}
break;
case have_pipe:
if(pid == 0)
{
if((pid2 = fork()) < 0)
{
perror("fork");
}
else if(pid2 == 0)
{
if(!find_command(command[0]))
{
printf("%s : command not found \n",command[0]);
exit(0);
}
if((fd = open("temporary",O_CREAT | O_RDWR | O_TRUNC , 0644)) == 0)
{
printf("temporary can't open\n");
exit(0);
}
dup2(fd,1);
execvp(command[0],command);
exit(0);
}
close(fd);
if((waitpid(pid2,&status2,0)) == -1)
{
perror("waitpid");
exit(0);
}

if(!find_command(pipe_next_command[0]))
{
printf("%s : command not found \n",pipe_next_command[0]);
exit(0);
}
if((fd2 = open("temporary",O_RDWR)) == 0)
{
printf("read temporary error!\n");
exit(0);
}
dup2(fd2,0);
execvp(pipe_next_command[0],pipe_next_command);
close(fd2);
if(remove("temporary"))
{
printf("remove error!\n");
}
exit(0);
}
break;
default:
break;
}

if((waitpid(pid,&status,0)) == -1)
{
perror("waitpid");
}
}

void my_shell(char *buf)
{
char command[max_command][max_input];
int count_command;
int flag;
char *cmd[max_input];
int i,background = 0;

while(1)
{
memset(buf,0,max_input);
printf("my_shell$:");
get_input(buf);
if(strcmp(buf,"exit\n") == 0 || strcmp(buf,"logout\n") == 0)
{
printf("exit!\n");
break;
}
else
{
count_command = explain_parameter(buf,command);
flag = explain_command(command,count_command,background);
if(flag == -1)
{
return ;
}
for(i=0; i< count_command; i++)
{
cmd[i] = (char *)command[i];
}
cmd[i] = NULL;
exec_command(cmd,flag,background);
}
}
}
int main( int argc, char *argv[] )
{
char *buf = NULL;

buf = (char *)malloc(max_input);
my_shell(buf);
if(buf != NULL)
{
free(buf);
}
return 0;
}