Linu学习总结(三)
文件时间属性修改与时间处理
如果要修改某特定文件的访问时间和修改内容时间,可以调用utime()函数
int utime(_const char *_file, _const struct utimbuf *_file_times)
struct utimbuf
{
_time_t actime;//访问时间
_tiem_t modtime;//修改内容时间
}
进程管理与程序开发
内核空间进程资源即PCB相关的信息。包含进程控制块本身、打开的文件表项、当前目录、当前终端信息、线程基本信息、可访问内存地址空间、PID、PPID、UID、EUID等。也就是说,内核通过PCB可以访问该进程所有的资源。这些资源只能通过系统调用才能访问。这一资源在当前进程退出,只能由另一进程来回收。
进程状态
用户级进程拥有以下几种状态:就绪/运行状态、等待状态(可以被中断打断)、等待状态(不可被中断打断)、停止状态和僵尸状态。
TASK_RUNNING:正在运行或处于就绪状态。就绪状态就是指进程申请到了除CPU外其他的所有需要的资源
TASK_INTERRUPTIBLE:处于等待队伍中,等待资源有效时唤醒,但可以被中断唤醒
TASK_UNINTERRUPTIBLE:处于等待队伍中,等待资源有效时唤醒,但不可以被中断唤醒。
TASK_ZOMBIE:进程资源用户空间被释放,但内核中的进程PCB并没有释放,等待父进程回收
TASK_STOPPED:进程被外部程序暂停(如收到SIGSTOP信号),当再次允许时继续执行(如收到SIGCONT信号),因此处于这一状态可以被唤醒。
进程基本属性
与进程本身相关的属性包括进程号(PID)、父进程号(PPID)、进程组号(PGID)。
进程号:是系统维护的唯一标识一个进程的正整数,进程号是无法在用户级层面修改的。在linux操作系统中,系统的第一个用户进程为init进程,他的PID为1,其他的进程PID依次增加。用户可以通过ps aux命令查看当前系统所有进程的基本属性
在应用编程中,调用getpid()函数可以获得当前进程的PID
_pid_t getpid(void);
如果执行成功将返回当前进程的PID,类型为pid_t;如果执行失败则返回-1
父进程号:任何进程(除init进程)都是有另一个进程创建,该进程称为创建进程的父进程,被创建的进程称为子进程。父进程的进程号(PID)即为子进程的父进程号
_pid_t getppid(void);
此函数如果执行成功将返回当前进程的父进程PID,类型为pid_t;如果执行失败则返回-1
进程组号:进程组是一个或多个进程的集合。他们与同一作业相关联,可以接受来自同一终端的各种信号,每一个进程组都有唯一的进程组号,进程组号可以在用户层修改
用户可以通过调用getpgid()函数来获得进程的进程组号
_pid_t getpgid(_pid_t _pid);
参数为要获得进程组号的进程号,如果为0表示获取当前进程组号,否则为指定进程的PGID。如果执行成功则返回进程的进程组号,否则返回-1.
函数pid_t getpgrp(void);也可以用来获取当前进程的进程组号
每一个进程组都可以有一个组长进程,组长进程的进程组号等于其进程号,但是进程可以先退出,只要在进程组中有一个进程存在,则该进程组就存在,与其组长进程是否终止无关。进程的最后一个进程可以终止,或者转移到另一个进程组
将摸个进程加到某个进程组的系统调用函数setpgid(),
int setpgid(pid_t pid, pid_t pgid);
其第一个参数为要修改进程PGID的进程PID,第二个参数为新的进程组号,如果两个参数相等,则有pid制定的进程变成进程组组长,如果pid为0,则修改当前进程的PGID,如果pgid是0,则由pid制定的进程的PID将用于进程组号的PGID
会话:(session)是一个或多个进程组的集合。系统调用的getsid()用来获取某个进程的会话SID
_pid_t getsid(_pid_t _pid);
如果pid是0,返回调用进程的会话号SID,一般来说,该值等于进程组号,如果pid并不属于调用者所在的会话,则调用者就不能获得SID
,某进程的会话SID是可以修改的,函数setsid()用来创建新会话
_pid_t setsid(void);
如果调用进程已经是一个进程组的组长,则此函数返回错误。
进程用户属性:linux是权限有严格控制的操作系统,某个进程拥有真实的用户号(RUID)、真实用户组号(RGID)、有效用户号(EUID)、有效用户组号(EGID)信息。
进程真实用户号(RUID):创建该进程的用户的UID为此进程的真实用户号。可以调用getuid()函数来获得当前的真实用户号
_uid_t getuid(void);
如果执行成功将返回当前进程的UID,如果执行失败,则返回-1
进程有效用户号(EUID):主要用于权限检查。多数情况下,EUID和UID相同。如果可执行文件的setuid位有效,则该文件的拥有者之外的用户运行该程序时,EUID和UID不相同,当设置了setgid位后,任何用户运行该程序时,其有效用户组EUID为该文件的拥有者 。
进程用户组号(GID):创建进程的用户所在的组号为该进程的进程用户组号,可以通过调用getgid()函数来获得当前进程的真实用户组号
_uid_t getgid(void);
执行成功将返回当前进程的GID;如果执行失败则返回-1
有效进程用户组好(EGID):一个情况下,EGID和GID相同,但是,当某可执行文件设置了setgid位,那么任何用户运行此程序时,其有效用户组号为该文件的拥有者所在的组
_uid_t getegid(void);
如果执行成功将返回当前进程的EGID;如果执行失败则返回-1
进程管理及控制
创建进程:在linux环境下,创建进程的主要方法是fork()函数
_pid_t fork(void);
如果执行成功,在父进程中奖返回子进程的PID,子进程将会返回0,以区别父子进程
如果执行失败,则在父进程中将返回-1
fork函数调用成功后,将为子进程申请PCB和用户空间。子进程会复制父进程几乎所以的信息,在用户空间将复制父亲用户空间所有的数据(代码段、数据段、BSS、堆、栈),子进程将会从父进程继承下列属性:有效用户/组号、进程组号、环境变量、对文件的执行的关闭标志、信号处理方式设置、信号屏蔽集合、当前工作目录、跟目录、文件模式掩码、文件大小限制,打开文件的描述符。
vfork()函数创建新进程时并不复制父进程的地址空间,而是在必要的时候才申请新的存储空间,vfork()比fork()可以很大程度上提高性能,vfork()只在需要的时候复制,而一般采用与父进程共享所有的资源的方式处理
_pid_t vfork(void);
vfork()在子进程环境中返回0,在父进程中返回子进程的进程号
在进程中运行新代码
用fork()函数创建子进程后,如果希望在当前进程中运行新的程序,则可以调用execX系列函数
execl()函数声明:
int execl(_const char *_path, _const char *_arg,...);
参数path字符串所指向的程序,第二个及以后的参数代表执行文件时传递的参数列表,最后一个参数必须是空指针以参数列表为空,如果执行成功,不返回,否则返回-1
execle()函数
int execle(_const char *_path, _const char *_arg,...)
execle()用来执行参数path字符串所指向的程序,第二个及以后参数代表执行文件时传递的参数列表,最后一个参数必须指向一个新的环境变量数组
execlp()函数
int execlp(_const char *_file, _cosnt char *_arg,...);
execlp()会从环境变量所指的目录中查找文件名为第一个参数指示的字符串,找到后执行该文件,第二个及以后的参数代表执行文件时传递的参数列表,最后一个参数必须用到空指针NULL
execv()函数
int execv (_const char *_path, char *_const _argv[]);
execv()用来执行参数path字符串所指向的程序,第二个参数为数组指针维护的程序参数列表。该数组的最后一个成员必须为NULL
execvp()函数
int execvp(_const char *_file, char *_const _argv[])
execvp()会从环境变量所知的目录中查找文件名为第一个参数所示的字符串,找到后执行该文件,第二个及以后的参数代表执行时传递的参数列表,最后一个成员必须为NULL
system()以新进程方式运行一个程序,然后结束。system()函数用来创建新进程,并在此进程中运行新进程,直到新进程结束后,才继续运行父进程。子进程结束后,会返回退出状态
int system(_cosnt char *_command)
回收进程用户空间资源
在linux系统下,可以通过以下方式结束进程
显示调用exit或_exit系统调用
在main函数中执行return语句
隐含的离开main函数,例如遇到main函数的“”}
函数exit()用于退出进程
void exit(int _status)
exit()与return的区别
return退出当前函数,exit()函数退出当前进程
return仅从子函数中返回,并不退出进程,调用exit()时要调用一段终止处理程序,然后关闭所有的I/O流。
_exit函数不调用任何注册函数而直接退出进程
void _exit(int _status);
_exit()仅把参数status返回给父进程而直接退出。此函数调用后不会返回,而是传递SIGCHLD信号给父进程,父进程可以通过
wait()函数获得子进程的结束状态,_exit()不会处理标准I/O缓冲区,如果要更新需要调用exit()
注册退出处理函数
函数atexit()和on_exit()用来注册在执行exit()函数前执行注册的操作函数
int atexit(void(*_func) (void));
int on_exit(void(*_func)(int_status, void *_arg),void *_arg);
两个函数的功能都是告诉进程,在正常退出时执行注册的func函数。两者的差异仅仅是atexit注册的函数没有参数。而on_exit注册的函数带参数,类型为void(*_func)(int _status, void *_arg)
第一个参数为退出的状态,在执行exit()函数时此参数值为exit()函数的参数
第二个参数为用户输入的信息,一个无类型的指针,用户可以指定一段代码位置或输出信息