オレンジ色
1. 端子
echo $$
現在の端末プロセスの ID を表示できます。
- デフォルトでは (リダイレクトなし)、各プロセスの標準入力、標準出力、および標準エラー出力は制御端末に送信されます。プロセスは標準入力から読み取り、つまりユーザーのキーボード入力を読み取り、プロセスは制御端末に書き込みます。標準出力または標準エラー出力 モニタに出力されます。
2. プロセスグループ
- プロセス グループとセッションは、プロセス間に 2 レベルの階層関係を形成します: プロセス グループは関連するプロセスの集合であり、セッションは関連するプロセス グループの集合です。プロセス合成セッションは、シェル ジョブ制御をサポートするために定義された抽象概念であり、ユーザーはシェルを通じてフォアグラウンドまたはバックグラウンドでコマンドを対話的に実行できます。
- プロセス グループは、同じプロセス グループ識別子 (PGID) を共有する 1 つ以上のプロセスで構成されます。プロセス グループには、グループを作成したプロセスであるプロセス グループ リーダー プロセスがあります。そのプロセス ID はプロセス グループの ID です。新しいプロセスは、親プロセスが属するプロセス グループ ID を継承します。
- プロセスグループにはライフサイクルがあります。開始時刻は、最初のプロセスがグループを作成する時刻であり、終了時刻は、最後のメンバー プロセスがグループを終了する時刻です。プロセスは、終了することによってプロセス グループから抜け出すことができます。別のプロセス グループに参加するため、プロセス グループを終了することもできます。プロセス グループのリーダー プロセスは、プロセス グループを離れる最後のメンバーである必要はありません。
3. 会話
- セッションはプロセス グループの集合です。セッション最初のプロセスは、新しいセッションを作成するプロセスであり、そのプロセスIDがセッションIDになります。新しいプロセスは、親プロセスのセッション ID を継承します。
一个会话中的所有进程共享单个控制终端。
制御端末は、セッション リーダーが端末デバイスを初めて開くときに作成されます。端末は、最大 1 つのセッションに対して制御端末になることができます。- いつでも、セッション内のプロセス グループの 1 つが端末のフォアグラウンド プロセス グループになり、他のプロセス グループはバックグラウンド プロセス グループになります。フォアグラウンド プロセス グループ内のプロセスのみが、制御端末からの入力を読み取ることができます。ユーザーが制御端末に端末文字を入力してシグナルを生成すると、そのシグナルはフォアグラウンド プロセス グループのすべてのメンバーに送信されます。
- 制御端末への接続が確立されると、セッションヘッドプロセスが端末の制御プロセスになります。
4. デーモンプロセス
- デーモン プロセス (elf プロセス) とも呼ばれるデーモン プロセスは、Linux のバックグラウンド サーバーです。これは存続期間の長いプロセスであり、通常は制御端末から独立しており、定期的に何らかのタスクを実行するか、何らかのイベントが発生するのを待ちます。一般に、d で終わる名前が使用されます。
- デーモン プロセスには次の特徴があります: 1. ライフ サイクルが非常に長い デーモン プロセスはシステムの起動時に作成され、システムがシャットダウンされるまで実行されます。2. バックグラウンドで動作し、制御端末を持ちません。制御端末が存在しないため、カーネルはデーモンの制御信号や端末関連の信号 (SIGINT、SIGQUIT など) を自動的に生成しません。
デーモンの作成手順:
- fork() を実行すると、親プロセスが終了し、子プロセスが実行を継続します。
- 子プロセスは、setsid() を呼び出して新しいセッションを開きます。
- プロセスの umask をクリアして、デーモンがファイルとディレクトリを作成するときに必要な権限を持っていることを確認します。
- プロセスの現在の作業ディレクトリを変更します。通常はルート ディレクトリ (/) に変更します。
- デーモンが親プロセスから継承した開いているファイル記述子をすべて閉じます。
- ファイル記述子 0、1、および 2 を閉じた後、通常、デーモンは /dev/null を開き、dup2() を使用してこれらすべての記述子がこのデバイスを指すようにします。
- コアビジネスロジック。
コード例:
/*
写一个守护进程,每隔2s获取一下系统时间,将这个时间写入到磁盘文件中。
*/
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <signal.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
void work(int num) {
// 捕捉到信号之后,获取系统时间,写入磁盘文件
time_t tm = time(NULL);
struct tm * loc = localtime(&tm);
// char buf[1024];
// sprintf(buf, "%d-%d-%d %d:%d:%d\n",loc->tm_year,loc->tm_mon
// ,loc->tm_mday, loc->tm_hour, loc->tm_min, loc->tm_sec);
// printf("%s\n", buf);
char * str = asctime(loc);
int fd = open("time.txt", O_RDWR | O_CREAT | O_APPEND, 0664);
write(fd ,str, strlen(str));
close(fd);
}
int main() {
// 1.创建子进程,退出父进程
pid_t pid = fork();
if(pid > 0) {
exit(0);
}
// 2.将子进程重新创建一个会话
setsid();
// 3.设置掩码
umask(022);
// 4.更改工作目录
chdir("/root");
// 5. 关闭、重定向文件描述符,先创建指向null的文件描述符fd,再把标准输入标准输出和标准错误重定向到null文件,
//否则的话使用printf打印的信息会直接输出到终端。而重定向后就会输入到我定向的文件中
int fd = open("/dev/null", O_RDWR);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
// 6.业务逻辑
// 捕捉定时信号
struct sigaction act;
act.sa_flags = 0;
act.sa_handler = work;
sigemptyset(&act.sa_mask);
sigaction(SIGALRM, &act, NULL);
struct itimerval val;
val.it_value.tv_sec = 2;
val.it_value.tv_usec = 0;
val.it_interval.tv_sec = 2;
val.it_interval.tv_usec = 0;
// 创建定时器
setitimer(ITIMER_REAL, &val, NULL);
// 不让进程结束
while(1) {
sleep(10);
}
return 0;
}
プログラムをコンパイルして実行する
最後に、設定した作業ディレクトリに time.txt ファイルが正常に作成されたことがわかります (この作業ディレクトリはプログラム内の子を使用して変更できます)。vim を参照すると、時間が継続的に time.txt ファイルに書き込まれていることがわかります。
注: ps aux を使用して、./daemon が存在することを確認します。このプロセスはデーモン プロセスであるため、制御端末から停止することはできません。強制終了できるのは、kill -9 pid を使用した場合のみです。