目次
2.無名のパイプライン(PIPE)と有名なパイプライン(FIFO)
(1) kill (シグナルを生成し、特定のプロセスを強制終了し、シグナルは生成されたシグナルをキャプチャします)
(7) sigqueue (誰に、信号が送信され、データが運ばれたか) (sigaction とのペア)
1. 6つのコミュニケーション方法
1. 名前付きパイプ (PIPE) と名前付きパイプ (FIFO)
2.信号
3. システム V-IPC の共有メモリ
4. システム V-IPC のメッセージキュー
5. システム V-IPC のセマフォ
6.ソケット
2.無名のパイプライン(PIPE)と有名なパイプライン(FIFO)
1.匿名パイプライン
(1) 特長
a. 同時に出て、同時に入る b. 名前がないとopenで開けない
c. 相対プロセス (父子プロセス、兄弟プロセス、祖父母プロセス) 間でのみ使用されます d. lseek() を使用して位置を特定することはできません
(2) パイプの使用
(3)注意点
a. パイプ内のパラメーターは、ファイル記述子を格納するために使用される 2 つの整数を含む配列であり、1 つは読み取り側で、もう 1 つは書き込み側です。
b. この図は、子プロセスが作成された後のパイプラインの状態を示しています
c. pipefd[0] --> 読み取りポート
pipefd[1] --> 書き込みポート
(4) コード
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
char * buf = NULL ;
int pipefd[2]
void f(void)
{
while(1)
{
printf("父进程*请输入:\n");
fgets(buf , 1024 , stdin );
int ret_val = write( pipefd[1] , buf , strlen(buf)+1 );
printf("成功写入:%d字节 \n" , ret_val );
ret_val = read( pipefd[0] , buf , 1024 );
printf("父进程*成功读取:%d字节 内容:%s \n" , ret_val , buf );
}
}
void s(void)
{
while(1)
{
int ret_val = read( pipefd[0] , buf , 1024 );
printf("子进程*成功读取:%d字节 内容:%s \n" , ret_val , buf );
printf("子进程*请输入:\n");
fgets(buf , 1024 , stdin );
ret_val = write( pipefd[1] , buf , strlen(buf)+1 );
printf("成功写入:%d字节 \n" , ret_val );
}
}
int main(int argc, char const *argv[])
{
if(pipe( pipefd))
{
perror("pipe error");
return -1 ;
}
buf = calloc(1, 1024);
int pid = fork();
if ( pid > 0 )
{
f();
}
else if (pid == 0)
{
s();
}
else
{
perror("fork error ");
}
return 0;
}
2. 有名なパイプライン (FIFO)
(1) FIFO の特徴
a. 名前があり、通常のファイル システムに保存されます b. open() を使用して、FIFO のファイル記述子を取得できます
c. 統一された read( )/write( ) を使用して読み書きする d. lseek( ) を使用して検索できない
e. 書き込みアトミシティにより、複数のライターがデータを互いに踏みにじることなく同時に書き込むことができます
f. First In First Out、FIFO に最初に書き込まれたデータが最初に読み出されます。
(2) FIFO の適用
(3) 注意事項
a. パイプライン ファイルが開かれるとき、当事者 (リーダー/ライター) が 1 つしかない場合は、ブロックして相手が到着するのを待ってから、同時にファイルを開きます。
(4)read.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define FIFO_PATH "/tmp/my_fifo"
int main(int argc, char const *argv[])
{
// 创建管道文件
if( access(FIFO_PATH, F_OK)) // 判断管道文件是否已存在 如果存在则返回 0 否则 -1
{
if( mkfifo(FIFO_PATH , 0666 )) // 创建
{
perror("mkfifo error");
return -1 ;
}
}
printf("管道文件创建成功!! \n") ;
// 打开管道文件
int fd_fifo = open(FIFO_PATH, O_RDONLY );
if (-1 == fd_fifo)
{
perror("open error");
return -1 ;
}
printf("管道文件打开成功!! \n") ;
// 读取信息
char buf[128]= {0};
int ret_val = read(fd_fifo , buf , sizeof( buf ));
printf("成功读取:%d 字节 内容:%s \n" , ret_val , buf );
// 关闭文件
close(fd_fifo);
return 0;
}
(5)write.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define FIFO_PATH "/tmp/my_fifo"
int main(int argc, char const *argv[])
{
// 创建管道文件
if( access(FIFO_PATH, F_OK)) // 判断管道文件是否已存在 如果存在则返回 0 否则 -1
{
if( mkfifo(FIFO_PATH , 0666 )) // 创建
{
perror("mkfifo error");
return -1 ;
}
}
printf("管道文件创建成功!! \n") ;
// 打开管道文件
int fd_fifo = open(FIFO_PATH, O_WRONLY );
if (-1 == fd_fifo)
{
perror("open error");
return -1 ;
}
printf("管道文件打开成功!! \n") ;
// 写入信息
int ret_val = write(fd_fifo , "hello Even" , sizeof("hello Even"));
printf("成功写入:%d 字节 \n" , ret_val);
// 关闭文件
close(fd_fifo);
return 0;
}
三、信号
1.注文
kill -l //システム内のシグナルをリストします
2. シグナル/イベントの生成方法
(1) ユーザー ボタン: ユーザーが特殊文字を使用して端末に渡すと、シグナル (イベント) が生成され、プロセスに配信されます。
(2) ハードウェア障害: 無効なメモリ アドレスへのアクセスなどのプロセス実行エラー。このとき、ハードウェアが最初にカーネルに報告し、次にカーネルがプロセスにイベントを配信します。
(3) kill 関数またはコマンド: 関数を介して、必要なイベントをプロセスに直接配信します。
3. 信号の種類
(1) 信頼できる信号:
(2) 信頼できない信号: 信号は発生しますが、失われる可能性があります
このうち、項目 1~31 は信頼できない信号であり、項目 34~64 は信頼できる信号です。
4.注意する
(1) シグナル SIGKILL および SIGSTOP は、無視、ブロック、またはキャプチャできない 2 つの特別なシグナルです。
(2) どのプロセスでも kill( ) 関数を使用して任意のシグナルを生成できます。
(3) シグナルを受信したターゲットプロセスは、次の順序で応答します。
A) シグナルがブロックされている場合は、シグナルを一時停止し、何もせず、ブロックが解除されるまで待ちます。それ以外はBへ。
B) 信号がキャプチャされている場合は、キャプチャの種類をさらに判断します。
B1) 応答関数が設定されている場合は、応答関数を実行します。
B2) 無視するように設定されている場合は、信号を直接破棄します。それ以外の場合は C に進みます。
C) シグナルのデフォルトアクションを実行する
(4) シグナル関数を子プロセスに継承できる
5.信号相関機能
(1) kill (シグナルを生成し、特定のプロセスを強制終了し、シグナルは生成されたシグナルをキャプチャします)
(2) シグナル (kill で使用)
(3)上げる
(4)一時停止(サスペンド)
(5) sigprocmask (ブロック/ブロック解除)
(6) シグナルセット操作機能群
(7) sigqueue (誰に、信号が送信され、データが運ばれたか) (sigaction とのペア)
運ばれる追加番号は、次の組合でなければなりません。
union sigval
{
int sigval_int;
void * sigval_prt;
};
(8)シグアクション
構造体 aigaction 関数
struct sigaction
{
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
void (*sa_sigaction)(int, siginfo_t *, void *);
6. ルーチン
(1) 子プロセスでシグナルを捕捉し、それに応じて応答する
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
void func(int arg)
{
printf("这里是信号响应函数 %d \n" , arg );//信号响应
}
int main(int argc, char const *argv[])
{
int pid = fork();
int i = 0 ;
if (pid > 0 )
{
printf("这里是父进程 \n " );
sleep(3);
printf("猎杀时间到了..。 \n " );
sleep(1);
kill(pid , 4 ); //产生信号
}
else if (pid == 0 )
{
signal( 4 , func);//捕获信号
while(1)
{
printf("这里是子进程 : %d \n ", i++ );
sleep(1);
}
}
return 0;
}
(2) 信号遮断の適用
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
void func(int arg)
{
printf("这里是信号响应函数 %d \n" , arg );
}
int main(int argc, char const *argv[])
{
// 设置信号响应的函数
signal( 3 , func );
signal( 4 , func );
// 初始化信号集
sigset_t set ;
sigemptyset( &set ); // 将信号集清空
sigaddset( &set , 3 ); // 将指定的一个信号添加到信号集中
sigaddset( &set , 4 ); // 将指定的一个信号添加到信号集中
// 设置阻塞信号集中的信号
sigprocmask(SIG_SETMASK , &set , NULL ); // 把信号集中的信号设置为阻塞状态
// 给自己发送 3.4 号信号
raise(3);
raise(4);
sleep(2);
// 解除阻塞
sigprocmask(SIG_UNBLOCK , &set , NULL ); // 把信号集中的信号设置为阻塞状态
return 0;
}
実行後、出力を開始する前に2秒待ってください。
(3) sigqueue と aigaction の適用
#include <stdio.h>
#include <signal.h>
#include <strings.h>
#include <sys/types.h>
#include <unistd.h>
void func(int sig, siginfo_t * info , void * arg )
{
printf("sig:%d , info: %s arg:%s \n" , sig , (char * )info->si_ptr , (char*)arg );
}
int main(int argc, char const *argv[])
{
// 定义ACT结构体并设置其信息
struct sigaction act ;
bzero(&act , sizeof(act)); // 清空结构体
act.sa_sigaction = func ;
act.sa_flags |= SA_SIGINFO ;//使用拓展信号函数而不是标准响应函数
// 设置捕获的信号响应函数
if( sigaction( 3 , &act, NULL ))//将信号捕获函数设置号
{
perror("设置捕获失败!!");
return -1 ;
}
// 设置好携带的参数
union sigval value;
value.sival_int = 1024 ; // 设置整型数组
value.sival_ptr = "Hello Even"; // 设置一个地址(指针)可以是任意类型的指针
// 发送信号
pid_t pid = getpid( );
if(sigqueue(pid , 3 , value))//发送信号,成功是0,失败是-1
{
perror("发送信号失败!!");
return -1 ;
}
printf("发送信号成功!!\n");
sleep(1);
return 0;
}