Linux C 编程之进程

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

注:本文所说的都是在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;
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值