1、进程标识符
进程的标识符类型:pid_t
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void); // 当前进程pid
pid_t getppid(void); // 父进程pid
2、FEW构建unix世界
2.1、fork进程产生
init进程:进程号为1号,是所有进程的祖先进程。
fork之后父子进程代码资源等完全一样。
父子进程区别:
1、返回值不一样;
2、pid与ppid不一样;
3、子进程不继承未决信号和文件锁;
4、子进程资源利用量清零。
在进程fork之前,要把进程所有的流进行刷新! fflush(NULL)
#include <unistd.h>
pid_t fork(void);
2.2、wait子进程回收和资源释放
父进程使用wait回收子进程的资源。
如果父进程结束了,子进程没有结束,子进程成为孤儿进程,由init进程对完成资源回收工作。
如果子进程结束了,但是父进程没有调用wait,子进程的资源无法释放成为僵尸进程。
进程分配的三种方法:分块法,交叉分配,池类算法。
#include <sys/types.h>
#include <sys/wait.h>
// 父进程回收子进程资源
pid_t wait(int *status); // 阻塞的
pid_t waitpid(pid_t pid, int *status, int options); // 可以非阻塞
/*
The value of pid can be:
< -1 meaning wait for any child process whose process group ID is
equal to the absolute value of pid.
-1 meaning wait for any child process.
0 meaning wait for any child process whose process group ID is
equal to that of the calling process.
> 0 meaning wait for the child whose process ID is equal to the
value of pid.
*/
/*
WIFEXITED(status)
returns true if the child terminated normally, that is, by call‐
ing exit(3) or _exit(2), or by returning from main().
WEXITSTATUS(status)
returns the exit status of the child. This consists of the
least significant 8 bits of the status argument that the child
specified in a call to exit(3) or _exit(2) or as the argument
for a return statement in main(). This macro should be employed
only if WIFEXITED returned true.
WIFSIGNALED(status)
returns true if the child process was terminated by a signal.
WTERMSIG(status)
returns the number of the signal that caused the child process
to terminate. This macro should be employed only if WIFSIGNALED
returned true.
*/
/*
The value of options is an OR of zero or more of the following con‐
stants:
WNOHANG return immediately if no child has exited.
WUNTRACED also return if a child has stopped (but not traced via
ptrace(2)). Status for traced children which have stopped
is provided even if this option is not specified.
WCONTINUED (since Linux 2.6.10)
also return if a stopped child has been resumed by delivery
of SIGCONT.
*/
2.3、exec函数族
在进程镜像替换之前,要把进程所有的流进行刷新! fflush(NULL)
#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[]);
int execvpe(const char *file, char *const argv[],
char *const envp[]);
/*
The exec() family of functions replaces the current process image with
a new process image.
*/
2.4、FEW的组合一个shell示例
示例1:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
int main()
{
pid_t pid;
puts("Begin");
fflush(NULL);
pid = fork();
if(pid < 0)
{
perror("fork");
exit(1);
}
if(pid == 0)
{
execl("/bin/date", "date", "+%s", NULL);
perror("execl()");
exit(1);
}
wait(NULL);
puts("End");
exit(0);
}
示例2:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <string.h>
#include <glob.h>
extern char **environ;
#define DELIMS " \t\n"
// 对输入的命令封装成一个结构体
struct cmd_st
{
glob_t globres;
};
static void prompt(void)
{
printf("myshell-0.1$ ");
}
// 对cmd进行解析
static void parse(char *cmd_str, struct cmd_st *cmd)
{
char *tok;
int i = 0;
while(1)
{
tok = strsep(&cmd_str, DELIMS);
if(tok == NULL)
break;
if(tok[0] == '\0')
continue;
glob(tok, GLOB_NOCHECK | GLOB_APPEND * i, NULL, &cmd->globres);
i = 1;
}
}
int main(int argc, char *argv[])
{
char *cmd_str = NULL;
size_t cmd_size = 0;
struct cmd_st cmd;
pid_t pid;
while(1)
{
prompt();
if(getline(&cmd_str, &cmd_size, stdin) < 0) // 从终端接收命令
break;
parse(cmd_str, &cmd);
if(0)
{}
else
{
pid = fork();
if(pid < 0)
{
perror("fork");
exit(1);
}
if(pid == 0) // 针对外部命令
{
execvp(cmd.globres.gl_pathv[0], cmd.globres.gl_pathv);
perror("execvp");
exit(1);
}
else
{
wait(NULL);
}
}
}
exit(0);
}
3、守护进程
#include <unistd.h>
pid_t setsid(void)
/*
setsid() creates a new session if the calling process is not a process
group leader. The calling process is the leader of the new session, the
process group leader of the new process group, and has no controlling ter‐
minal. The process group ID and session ID of the calling process are set
to the PID of the calling process. The calling process will be the only
process in this new process group and in this new session.
-----------------------------------------------------------------------------------*/
#include <unistd.h>
int setpgid(pid_t pid, pid_t pgid);
pid_t getpgid(pid_t pid);
4、系统日志
#include <syslog.h>
// opens a connection to the system logger for a program.
void openlog(const char *ident, int option, int facility);
// generates a log message, which will be distributed by syslogd
void syslog(int priority, const char *format, ...);
void closelog(void);
/*
option
...
LOG_PID Include PID with each message.
...
facility
...
LOG_DAEMON system daemons without separate facility value
...
level
LOG_EMERG system is unusable
LOG_ALERT action must be taken immediately
LOG_CRIT critical conditions
LOG_ERR error conditions
LOG_WARNING warning conditions
LOG_NOTICE normal, but significant, condition
LOG_INFO informational message
LOG_DEBUG debug-level message
*/
系统日志示例:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <syslog.h>
#include <string.h>
#include <errno.h>
#define FNAME "/tmp/out"
static int daemonize(void)
{
int fd;
pid_t pid;
pid = fork();
if(pid < 0)
return -1;
if(pid > 0)
exit(0);
fd = open("/dev/null", O_RDWR);
if(fd < 0)
return -1;
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
setsid();
chdir("/");
return 0;
}
int main()
{
FILE *fp;
int i;
openlog("mydaemon", LOG_PID, LOG_DAEMON);
if(daemonize())
{
syslog(LOG_ERR, "daemonize() failed!");
exit(1);
}
else
{
syslog(LOG_INFO, "daemonize() start!");
}
if(daemonize())
{
exit(1);
}
fp = fopen(FNAME, "w");
if(fp < 0)
{
syslog(LOG_ERR, "fopen failed: %s.", strerror(errno));
exit(1);
}
syslog(LOG_INFO, "%s was opened.", FNAME);
for(i = 0; ; i++)
{
fprintf(fp, "%d\n", i);
fflush(fp);
syslog(LOG_DEBUG, "%d is printed.", i);
sleep(1);
}
exit(0);
}
单实例守护进程:锁文件/var/run/name.pid
启动脚本文件:/etc/rc*
总结
以上是自己对进程内容的总结,后续还会在此基础上慢慢的补充和完善。