Linux システム プログラミング プロセス スレッド

Linux システム プログラミング プロセス スレッド


この記事では主に、
プロセス スレッド
、プロセスとスレッドの基本概念、
プロセスの作成方法、
プロセス間の通信方法、
スレッドの作成
方法、スレッド間の同期方法 を紹介します。

プロセススレッドの学習の初日

1. プロセスと手順

プロセス: 実行中のプログラムはプログラムの実行プロセスでもあり、プロセスはメモリ内で実行されます。プロセスには実行中に特定のリソースが割り当てられます。

プログラム: 静的であり、ディスク上に a.out が存在すると理解できます。

注意:进程是程序执行和资源管理的最小单位。

スケジューリングアルゴリズム: 先入れ先出し/ショートプロセスファースト/高優先度ファースト/タイムスライスローテーション

2. プロセスの分類

対話型プロセス: シェルによって制御および実行され、端末に関連付けられます。対話型プロセスはフォアグラウンドまたはバックグラウンドで実行できます。

フォアグラウンドプロセス: ターミナルを占有するプロセス、その他はバックグラウンドプロセスと呼ばれます

バックグラウンドプロセス:端末を占有しないプロセス

デーモン プロセス: バックグラウンドで実行されます。通常、Linux の起動時に実行されます。システムがシャットダウンされたときにのみ終了します。バッチ プロセス: ターミナルに属さず、キューに送信され、順次実行されます。

孤立プロセス: 親プロセスが子プロセスを作成したが、親プロセスが終了し、子プロセスが終了しない場合、このプロセスは init プロセス (プロセス 1 とも呼ばれます) に引き継がれ、init プロセスは孤立したプロセスの親プロセス。

フォアグラウンド プロセスをバックグラウンド プロセスに変換します
。 ctrl+c でプロセスを終了し、プロセスを終了してシェルに戻ります。 ctrl+z で一時停止します。フォアグラウンド プロセスをバックグラウンド プロセスに変換し、シェルに戻ります。プロセスはジョブ
を終了していません。
現在バックグラウンドで実行中のプロセスのプロセス pid を表示します (コマンド ジョブ - l)
fg + n ここで、n はジョブのシリアル番号であり、pid の値ではありません。バックグラウンドで一時停止されており、プログラムは終了しません。(fg 1)
& 実行可能プログラムの後にアドレス記号を追加すると、プロセスはデフォルトでバックグラウンド プロセス (./a.out &) に変換されます。現在のターミナルとは関係がなく、終了できず、 ctrl+c および ctrl+z で一時停止 (追加が必要)
bg N フォアグラウンド プロセスをバックグラウンド プロセスに変換します。(bgn)

2. 処理状況

 新建状态:应用程序被创建时的状态,没有进入到就绪队列中。
  就绪状态:进行已经具备运行条件,等待系统分配处理器运行(放入到就绪队列中)
  运行状态:进程正在运行
  阻塞状态:又称之为等待状态或者睡眠状态。进程在等待一个信号或者系统资源
  停止:也叫死亡状态,进程完成任务后正常结束。
 进程的三要素:
       每个进程都有进程id,是唯一的标志
       每个进程都有pcb,内核中秒数进程的主要数据 一个结构体
       每个进程都会进行内存映射。     

2. 処理コマンド

 ps: 列出活跃的进程
 ps -au  列出所有进程  但进程都和终端有关系
 ps -aux  列出所有进程,包括有关系和终端没关系的进程。
 top  动态显示进程信息,等价于任务栏管理器
 top -d  n秒   每隔n秒刷新一次信息。
 pstree 打印进程的树状信息,关系信息。
 ps -ef  标准的格式显示系统的进程信息
 kill  发送信号给进程
 列出所有信号   kill -l
 给进程发信号  kill -信号  PID  
 1) SIGHUP  终端关闭会发送               进程结束
 2) SIGINT   ctrl + c 终止当前进程      进程结束 
 3) SIGQUIT  ctrl + \  停止当前进程     进程结束
 9) SIGKILL    杀死进程                       进程结束		
12) SIGUSR2   用户自定信号        
14) SIGALRM   闹钟信号
19) SIGSTOP	 进程暂停
20) SIGTSTP   ctrl+z  挂起进程        转换成后台进程

3. プロセス API 関数

1.プロセスIDの取得

 函数原型  pid_t getpid(void);
 头文件: #include <sys/types.h>         #include <unistd.h>
  返回值: 当前进程的进程id号

   函数原型:pid_t getppid(void);
  作用: 获取当前进程的父进程id号
  练习:把当前进程的进程id和父进程的进程id打印在屏幕上

2. 子プロセスの作成 (fork と vfork の違い)

2.1 fork()、関数プロトタイプ pid_t fork(void); 子プロセスを作成し、親プロセスのすべての特性を複製し (親プロセスのメモリ空間も複製します)、親プロセスと子プロセスは影響を受けません。
父进程改变某一个变量,子进程不改变。返回值有2个,返回给父进程的是子进程的PID,返回给子进程的是0,如果失败返回-1;
2.2 vfork() は、子プロセスの作成に使用されるプロトタイプ pid_t vfork(void) を置き換え、また 2 つの値を返します。親プロセスは子プロセスの pid を返し、子プロセスは 0 を返しますが、子プロセスは、親プロセスのメモリ空間。

親プロセスのメモリは共有的にアクセスされ、親プロセスのメモリが変更されると、子プロセスも同時に変更します。vfokでは子プロセスが先に実行され、子プロセスが終了してから親プロセスが実行されます。

2.3 clone() は、Linux カーネルがプロセスを作成する方法です。clone 関数は、プロセスとスレッドの作成に使用されます。移植には適さないため、開発中は使用しないようにしてください。

练习: 父子进程执行不同的代码
 #include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
printf("danny帅\n");
pid_t pd = fork();
//子进程执行pid == 0中的代码
if(pd == 0)  {    while (1) {    printf("我是子进程\n");  }}
//父进程执行else中的代码
else {  while (1) {printf("----我是父进程--------\n");   }}
printf("pid = %d\n",pd);
printf("好帅\n");
//从fork开始的代码,在父进程和子进程中都有一份
return 0;
}

書き込み操作のコピー テクノロジ: フォークは新しいプロセスを作成しますが、親プロセスのコピーは生成しません。子プロセスが親プロセスの内容を変更する必要がある場合、変更が必要なメモリ空間をコピーします。親プロセスも同様です。
vfork を使用して子プロセスを作成すると、パブリック変数 x が親プロセスと子プロセスによって別々に出力されます。

4. exec シリーズの関数:

作用:在一个进程中执行另外一个进程,例如在a.out进程中执行b.out
   #include <unistd.h>
   extern char **environ;    全局变量,已经定义好了,直接声明后使用,字符串的首地址,环境变量。

4.2 関数プロトタイプ: int execl(const char *path, const char arg, … / (char *) NULL */);

         函数作用:列举的方式传参
         函数参数:path 可执行程序的位置
                          arg   参数  需要执行的命令  可变长。
         返回值: 失败返回-1  成功返回0错误信息存在errno中

4.2 関数プロトタイプ: int execlp(const char *file, const char arg, … / (char *) NULL */);

        作用:优先到PATH路径中查找,其他功能和execl一样。

   int execle(const char *path, const char *arg, ...   /*, (char *) NULL, 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[]);

課題: 4 つの関数を自分で学習し、テスト コードを作成します。

プロセススレッド学習2日目

1. exec シリーズの関数:

  作用:在一个进程中执行另外一个进程,例如在a.out进程中执行b.out
  特点: exec 执行后他取缔了原来进程的数据段,代码段,堆栈,执行完成后,原来调用的进程内容除了进程号外,其他内容全部替换。
   使用: 如果当前进程想执行另外一个进程,但自己没有其他事情可做,自己结束执行exec中的进程。 
  #include <unistd.h>
   extern char **environ;    全局变量,已经定义好了,直接声明后使用,字符串的首地址,环境变量。

4.2 関数プロトタイプ: int execl(const char *path, const char arg, … / (char *) NULL */);

         函数作用:列举的方式传参
         函数参数:path 可执行程序的位置
                          arg   参数  需要执行的命令  可变长。
         返回值: 失败返回-1  成功返回0错误信息存在errno中
         案   例:execl("/bin/ls" ,"ls","-l",NULL);

4.2 関数プロトタイプ: int execlp(const char *file, const char arg, … / (char *) NULL */);

        作      用:优先到PATH路径中查找,其他功能和execl一样。
        参      数:   file   文件名   (会在path路径中查找)
                           arg后的参数和execl一样

     int execle(const char *path, const char *arg, ...   /*, (char *) NULL, char * const envp[] */);
     作     用:  在envp中查找执行程序和命令

    int execv(const char *path, char *const argv[]);
     作     用: 在数组中寻找执行命令

    int execvp(const char *file, char *const argv[]);
     作    用: 执行文件在file中查找但其他命令在数组中查找

    int execvpe(const char *file, char *const argv[],  char *const envp[]);
     作    用: 在path中查找执行文件,其他命令在数组和环境变量中查找。

  总结:  l   列举的方式   list
              v  数组的方式传参   数组也要NULL结束
              p  可执行程序名再PATH路径中查找
              e  环境变量传参

2. プロセスを終了します

  进程的终止:第一种 自愿终止,main函数return 
                     第二种:被迫终止, 调用exit系列函数。
                                                    接受信号也会终止
   原理:当进程结束时,内核通知父进程,在父进程处理前,这个子进程是僵尸进程,占用的各种资源被回收,进程描述符任然存在。
     #include <stdlib.h>

関数プロトタイプ: void exit(int status);

     作用:退出进程
     参数: status 状态码,给到父进程
     特点: 做善后处理。刷新缓冲区,释放放缓冲区,退出进程,调用了_exit

     #include <unistd.h>

関数プロトタイプ: void _exit(int status);

     作用:退出进程
     参数: status 状态码,给到父进程
     特点: 立马退出,直接退出、
  面试题:请讲下 exit()和_exit的区别:_exit()执行后会立即返回给内核,而exit()会做一些善后处理,然后将控制权交给内核。

3. プロセスのブロック

 #include <sys/types.h>
   #include <sys/wait.h>

関数プロトタイプ: pid_t wait(int *status);

   作   用:     等待子进程结束,堵塞函数。只要有进程结束则立马返回,不管是哪个进程。
   参   数:    status  子进程退出时候的状态码
                    如果不关心子进程的退出码 则直接传入NULL
   返回值: 如果成功返回子进程的id 失败返回-1; errno
                  在等待所有进程,只要有一个进程结束  wait就会返回。
    
    WEXITSTATUS(status)
     状态信息需要通过当前宏的修改才能使用,不可以直接使用wait的状态信息。

 练  习: 请创建3个子进程,保存进程id号,然后父进程等待所有子进程结束后打印出结束后的子进程id。

関数プロトタイプ: pid_t waitpid(pid_t pid, int *status, int options);

   作用: 等待某一个进程结束,或者某几个进程结束。
   参数: pid 需要等待的进程id
             status  状态码 是子进程中exit的传出值
             options   是0表示堵塞。   WNOHANG 是非堵塞(不等待)
    pid的可能值如下:
     < -1  等待进程组id为pid绝对值的组下任意一个子进程id.

     -1     等待任意的子进程,等价于wait

     0      等待任意的进程  这个进程组的id是等于调用的进程id.

    > 0   等待进程id是pid的子进程结束。.

   进程组: 当运行某一个可执行程序,创建一个进程。同时会创建一个进程组,这个进程组的id就是当前进程的id,如果这个父进程创建了子进程,
	这些子进程都有自己的pid,他们都属于父进程的组id中,他们属于同一个组。

 练习: 请创建三级进程  父进程  子进程  孙子进程 在子进程中等待孙子进程  在父进程中等待子进程。等子进程结束 则父进程也一起结束。

4. デーモンプロセス

定義: バックグラウンド プロセスとも呼ばれるデーモン プロセスは、通常、割り込みから独立しており、通常、Linux の起動時に実行されます。

 终端:是系统和用户交互的界面,从当前终端产生的进程都依附于当前终端。如果当前中断关闭,对应的前台进程会自动关闭,但是守护进程突破此现值,

デーモンの手順:

  第一步:创建子进程,父进程退出
              if(fork()  > 0 ){  exit(0);}
   第二步:在子进程中创建新的会话。(会话中 各种进程组)
            setsid    用来创建一个新的会话,并且当前进程成为新会话的组长。
   第三步:设置文件的权限掩码。增加守护进程的灵活性
            umask(0);
    第四步:更改当前目录
     chdir 改变当前目录。  一般情况下修改成根目录或者/temp 为守护进程的当前目录
再将父进程的三个默认打开的文件重定向  dup2();
    第五步: 关闭文件描述符。
          原因:新建的子进程会继承父进程的所有打开的文件描述符。(fork)
                   在完成会话后,为了防止资源的浪费。关闭不用的文件。
                     close 函数 或者fclose
         getdtabsize 可以获取最大的文件描述符。  sysconf()

5. システムログとメイン関数の影響

  main函数善后   void (*function)(void)
  #include <stdlib.h>
   函数原型:int atexit(void (*function)(void));
   函数作用:main函数接受后需要做的时期,可以调用的函数。
   函数参数: (*function)  函数指针,返回值是void 参数是void的函数
   
  #include <stdlib.h>

   int on_exit(void (*function)(int , void *), void *arg);
   函数作用:main函数接受后需要做的时期,可以调用的函数。
   函数参数:(*function) 函数指针,返回值是void 参数是void的函数
                 
 系统日志:
  使用原因:系统日志文件
  打开系统日志文件
  #include <syslog.h>

   void openlog(const char *ident, int option, int facility);
   参数: ident    提示字符串
              option:LOG_PID    把消息加入到进程id中
              int facility : LOG_DAEMON  守护进程。 
             
   void syslog(int priority, const char *format, ...);
   作用:写日志,
             priority 优先级   LOG_INFO  普通日志
                                       LOG_ERR   错误消息
             需要写的内容
    
   void closelog(void);
    作用:关闭日志文件
    
 作业:把当前进程的进程id 写入到系统日志文件中,然后创建2个子进程,分别写5条日志到系统日志中。主进程等待所有子进程结束。后关闭日志日志文件。

プロセスとスレッドの学習 3 日目

マルチプロセス通信
1. 初期:名前なしパイプ 名前付きパイプ信号
IPC:共有メモリセマフォ情報キュー
ネットワーク:ソケット通信

パイプライン通信:

2. 名前のないパイプ

是一个文件,系统维护的一个文件,内核中。
特点: 只能用于亲缘关系的进程之间(父子  子孙..)
           半双工的通信方式,同一个时间只可以由一个方向发给另外一个方向
           有固定的读写端
           管道可以看成是特殊的文件,对于他的读写可以用read和write函数
           基于文件描述符的通信方式,当一个管道建立,有两个描述符
           fd[0]用于读文件    fd[1]用来写文件
関数プロトタイプ: int Pipe(int Pipefd[2]); [レポート]

ヘッダーファイル: #include <unistd.h>
機能: 名前のないパイプを作成する
パラメーター: fd、fd[0]、fd[1] の配列
戻り値: 成功した場合は 0、失敗した場合は -1 を返します。エラー情報は次の場所に格納されます。エラーノ

注: 書き込みパイプがある場合は、読み取りパイプも存在する必要があります。そうでないとバーストします。
書き込みエンドが存在する場合:
パイプにデータがある: read は、実際に読み取られたデータのバイト数を返します。
パイプ内にデータがありません: 読み取りはブロック状態にあり、パイプ内にデータが存在するまでブロックは解除されません。
読み取りデータがある場合、書き込みエンドが存在しない場合、読み取りは常にブロックされます。書き込みの場合、読み取りは常にブロックされます。 end が存在する場合は表示されません。

3. 有名なチャンネル

 为了解决不相关的进程之间的通信,也是一个文件。
関数プロトタイプ: int mkfifo(const char *pathname, mode_t mode); [レポート]
   头  文  件:     #include <sys/types.h>       #include <sys/stat.h>
   作      用: 创建有名管道,管道名字叫pathname
   参     数:  pathname,   路径 也叫管道名
                    mode         创建管道文件的模式  0666
    返回值: 如果成功返回0  失败返回-1

画面に入力した内容をパイプに書き込む処理を記述し、2番目の処理がそれを読み出します。

二、信号

理解する: プロセス通信の方法では、データは転送されず、通知のみが転送されます。シグナルは割り込み、非同期通信方法として理解でき、シグナルはユーザー空間とカーネル空間の間で相互作用できます。
信号処理方法:
信号を無視: 信号に対して処理は行われませんが、無視できない信号が 2 つあります。SIGKILL SIGSTOP で
信号をキャプチャします。信号処理関数を定義します。信号が発生すると、対応する関数が実行されます
。デフォルトの動作: Linux では、各 Signal にデフォルトの動作があります。

信号命令: kill -命令  pid
注意:编号为1到31的信号是传统的unix支持的信号,是不可靠信号(非实时),不存储,不放入信号队列。信号容易丢失,不排队速度快
        32~63 信号,是扩展信号,叫做可靠信号,存入消息队列,不会丢失。相对来说速度不够快。
 信号处理函数:

   函数原型:int kill(pid_t pid, int sig);  【重】
   头文件:   #include <sys/types.h>         #include <signal.h>
   参  数: pid 需要发送哪个进程的id,   sig 是需要发送的信号
                > 0   发送sig信号给pid的进程(一个进程)
                0      发送给正在调用的进程组所在进程下的所有id
                -1   发送sig信号给所有进程(除了1号init进程)
                <-1 给进程组为绝对值pid的组发送sig信号。
   返回值:如果成功返回0 如果失败返回-1  错误信息存入errno

  #include <signal.h>

   函数原型: int raise(int sig);
   作       用: 给当前进程发送信号,相当于 kill(getpid(),sig)
   参数:    需要放的信号内容
    返回值: 如果成功返回 0,失败返回-1,错误信息errno

ジョブ: 名前付きパイプを使用してサーバーとクライアントを書き込みます。クライアント
: 親プロセスは 1 秒ごとに子プロセスを生成します。各子プロセスは、独自の PID と現在のシステム時刻を名前付きパイプに書き込みます。サーバー: 名前なしパイプからデータを読み取ります
。そして画面に印刷します。

アラーム信号:

3. 目覚まし時計機能を設定します。

  函数原型:unsigned int alarm(unsigned int seconds);  【重】
  头文件: #include <unistd.h>
  作用:在参数seconds秒后发送一个闹钟给自己,信号名称:SIGALRM---14
  返回值: 如果先前没有设置闹钟,成功返回0,失败返回-1
                如果之前设置了闹钟,返回之前设置的闹钟剩余秒数,
  注意: 一个进程只可以设置一个闹钟,不可以多个,当第二次设置闹钟的时候,不会成功,只会返回第一个闹钟剩余的时间。等价于得到闹钟的剩余秒数。

現在のプロセスをブロックする
関数プロトタイプ: intポーズ(void);
ヘッダーファイル: #include <unistd.h>
関数: 現在のプロセスをブロック状態にし、シグナル(終了シグナルまたはシグナル処理を引き起こすシグナル)の受信を待機します。呼び出される関数) が
終了されていない場合、信号またはキャプチャする必要のない信号はブロック解除されません。

一時停止と待機の違い:

前者は別のプロセスが sigkill シグナルを送信するのを待っていますが、wait は親プロセスが子プロセスの終了を待っています。

信号処理機能:

関数プロトタイプ: sighandler_t signal(intsignum, sighandler_t handler); [レポート]
   回调函数:  typedef void (*sighandler_t)(int);
   头文件:      #include <signal.h>
   参数:       signum  信号的值,需要处理什么信号
                    handler 参数:
                   如果想忽略信号(SIG_IGN)    1
                   如果想默认操作(SIG_DEL)0
                   对信号自定义处理的回调函数地址

  返回值:返回先前处理函数的指针,如果没有先前的处理函数则返回自己。如果失败返回SIG_ERR  (-1)
    
   练习:请自定义处理ctrl+z 信号。  (我是ctrl+z)

 SIGUSR1
  练习: 写一个代码,让子进程每隔5秒给父进程发送一个消息 ,父进程得到消息后,在屏幕上打印一句话。  (day03/09childContFather.c)

4. 共有メモリ:

定义: 共享内存是最高效的进程间通信方式。进程之间可以直接读写内存。不需要其他的数据拷贝。一般情况下,共享内存是不安全的,
在写的过程中是可以立马读的,所以数据有可能不完整。为了解决这个问题,需要用到锁机制。
 流程:  【重】
  1.创建或者打开共享内存  shmget函数
  2.映射共享内存    shmat 函数
  3.内存的读写。 使用指针读写。
   4.删除共享内存    shmdt    (shmctl) 

関数プロトタイプ: int shmget(key_t key, size_t size, int shmflg); [Heavy]

  头   文  件:#include <sys/ipc.h>         #include <sys/shm.h>  
  作        用 : 创建或者打开共享内存。
  参          数:key 是内核识别ipc的一个标志。
                       两种获取办法: ftok获取   第二种方式:系统自动给与  IPC_PRIVATE
                      size 共享内存的大小,以字节为单位,如果是0则是获取共享内存。
                       shmflg:权限, IPC_CREAT|0666   如果不存在则创建,如果存在则打开  
 返  回  值: 返回key相关的共享内存的id,如果失败返回-1,如果key相同则id也相同。

関数プロトタイプ: key_t ftok(c​​onst char *pathname, int proj_id);

   头  文  件:#include <sys/types.h>           #include <sys/ipc.h>
   作       用:根据路径名和id产生一个唯一的pic的key值。
   参       数:pathname  一个路径,相同的路径和相同的id产生的key值相同
                    id     工程的id,自定义的,任意8位都行
   返  回  值:如果成功返回 key值,如果出错返回-1

関数プロトタイプ: void *shmat(int shmid, const void *shmaddr, int shmflg); [重い]

   头  文  件:#include <sys/types.h>           #include <sys/shm.h>
   作       用:将申请到的共享内存空间映射到4G的虚拟内存的某一个位置。
   参       数:shmid,共享内存的id 是shmget函数的返回值
                    shmaddr  需要映射的地址,一般情况下是NULL,系统自动分配
                    shmflg  标志,一般情况下写0 表示可读可写。
   返  回  值:如果成功返回 映射的首地址,如果出错返回-1

関数プロトタイプ: int shmdt(const void *shmaddr);

   函数作用:讲共享内存从映射中删除。
   函数参数:shmaddr 是shmat的返回值,也是映射的地址。
   返回值:  如果成功返回0 失败返回-1

    #include <sys/ipc.h>
   #include <sys/shm.h>

関数プロトタイプ: int shmctl(int shmid, int cmd, struct shmid_ds *buf); [重い]

   函数参数:shmid  是共享内存的id  是shmget的返回值
                    cmd   是命令,需要控制共享内存的命令
                              IPC_STAT  获取共享内存的信息  存入到buf中
                              IPC_SET   设置共享内存的信息。
                              IPC_RMID  删除共享内存。注意和shmdt的区别
   函数作用:  可以控制共享内存
   返回值:    如果成功返回0 失败返回-1   

  struct shmid_ds {
           struct ipc_perm shm_perm;    /* 操作权限,是三种ipc的共有的结构体 */
           size_t          shm_segsz;   /* 共享内存的大小,字节数*/
           time_t          shm_atime;   /* 最后加载的时间 */
           time_t          shm_dtime;   /* 最后离开的时间 */
           time_t          shm_ctime;   /* 最后修改时间 */
           pid_t           shm_cpid;    /* 创建共享内存的进程id */
           pid_t           shm_lpid;    /* 在该段 shmat的进程id */
           shmatt_t        shm_nattch;  /* 使用该共享内存的进程数目*/
           ...
       };

#include <sys/mman.h>
自行询: void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);

プロセスとスレッドの学習 4 日目

メッセージキュー (プロデューサー/コンシューマーモデル)

メッセージキュー: メッセージキューはプロセス間通信方式である ipc シリーズのオブジェクトであり、
各メッセージキューは固有の ID を持っています。
ユーザーはメッセージ キューにメッセージを追加したり、メッセージを読み取ったり (データの送受信) できます。

プログラミング手順:

               1、得到key值  ftok
               2、得到消息队列的id, msgget
               3、数据的收发   msgsnd   msgrcv
               4、删除消息队列 msgctl

関数プロトタイプ: int msgget(key_t key, int msgflg);

  头 文  件:       #include <sys/types.h>       #include <sys/ipc.h>       #include <sys/msg.h>
  函数作用:创建消息队列并且返回消息队列的id值。
  函数参数:  key值,ftok的返回值,IPC_PRIVATE
                    msgflg  IPC_CREAT |0666

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

関数プロトタイプ: int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

   函数作用: 往消息队列发送数据  (和write有点相似)
   函数参数: msgid   是消息队列的id值
                     msgp   需要发送数据的缓存  (需要有自己固定的结构体)
                     struct msgbuf {
                                  long mtype;       /* 大于0的消息类型 */
                                 char mtext[1];    /* 需要发送的数据,正文内容 */
                      };

                    msgsz   发送数据的大小 ,实际发送的正文内容的大小
                    msgflg   如果是0则表示堵塞,发送完毕后再返回,如果不堵塞IPC_NOWAIT
   返回值: 如果成功返回0  失败返回-1

関数プロトタイプ: ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

   函数作用: 接受消息队列中数据  (和read有点相似)
   函数参数: msgid   是消息队列的id值
                     msgp   需要接受数据的缓存
                    msgsz   发送数据的大小
                    msgtyp  消息的类型(消息的范围)
                          0    消息队列中的第一个消息。
                         >0  接受消息队列中第一个msgtyp类型的消息
                         <0  接受消息队列中 不大于msgtyp  类型的绝对值的最小类型的第一个消息。
                    msgflg   如果是0则表示堵塞,发送完毕后再返回,如果不堵塞IPC_NOWAIT


 #include <sys/types.h>
   #include <sys/ipc.h>
   #include <sys/msg.h>

関数プロトタイプ: int msgctl(int msqid, int cmd, struct msqid_ds *buf);

  函数参数: msqid,   消息队列的id值
                     cmd,  需要控制消息队列的命令
                    IPC_SET    设置消息队列的属性
                    IPC_STAT  获取消息队列的状态
                    IPC_RMID 删除消息队列
  函数作用: 控制消息队列(关闭 获取 设置)
  返 回 值: 如果成功返回0  失败返回-1

セマフォ: セマフォとも呼ばれます。これは、プロセスまたはスレッド間の同期メカニズムです。(重要なリソースのロック)

エンコード手順:

0、或者key值,ftok
1、打开或者创建信号量   semget       (semaphore)
2、信号量的初始化(semctl) 不一定需要
3、p、v操作  semop()
4、删除信号量   semctl

関数プロトタイプ: int semget(key_t key, int nsems, int semflg);

   头  文 件:  #include <sys/types.h>       #include <sys/ipc.h>       #include <sys/sem.h>
   函数作用:创建或者打开信号量
   函数参数:key 是ipic的key值,第一种ftok   IPC_PRIVATE
                    nsems  信号量的个数 如1 ,2
                     semflg     IPC_CREAT   | 0666;
   返回值:  如果成功返回信号量的id  失败返回-1

注: p 操作は、別のプロセスがウェイクアップするまで、現在のプロセスの実行ステータスをブロック状態に設定します。空のリソースを申請します (セマフォは 1 つ減ります)。申請が成功すると、直接終了します。
失敗すると、プロセスはブロックされ、プロセス v が動作するまで待機します。
v 操作は、ブロックされたプロセスをウェイクアップする (リソースを解放する) 役割を果たします (セマフォを 1 つ増やします)。

関数プロトタイプ: int semop(int semid, struct sembuf *sops, size_t nsops);

   函数参数:semid 信号量的id  semget函数的返回值  
              struct sembuf {            
                    unsigned short sem_num;  /* 信号的第几个。信号量的编号 */
                    short          sem_op;   /* 信号量的pv操作,如果是-1则是p操作,如果是v则1*/
                    short          sem_flg;  /* 标志位 默认为0 */
                  };
               nsops : 需要操作的信号量的个数
   函数作用: 给信号量做pv操作,p则信号量减一  v是信号量加1
  返回值:成功返回信号量的标识符  失败返回-1
  头文件:  #include <sys/types.h>       #include <sys/ipc.h>       #include <sys/sem.h>

関数プロトタイプ: int semctl(int semid, int semnum, int cmd, …);

   函数作用: 删除 修改  初始化 信号量  做信号量的操作
   函数参数: semid    信号量的id 是semget函数的返回值
                    cmd   操作信号的命令
                    IPC_RMID   删除信号量
                    SETVAL   设置信号量的值
                    GETVAL  获取信号量的值
                    semnum   信号量的编号。使用单个信号量的时候 默认是0
                   第四个参数:
                    union semun {   //当前联合需要自行定义
                             int              val;    /* 设置信号量的时候使用 */
                             struct semid_ds *buf;    /*IPC_STAT, IPC_SET的时候需要的buf结构体指针 */
                             unsigned short  *array;  /* 设置多个信号量的时候 数组指针 */
                             struct seminfo  *__buf;  /* IPC_INFO  */
       };

     返回值: 如果是GETVAL 成功返回信号量的值,失败返回-1
                   如果是SETVAL 成功返回0  失败返回-1

スレッド作成スレッド同期

スレッドとプロセスの違いは次のとおりです。

 进程: 独占4g的内存空间
             linux内核 对每个进程都要pcb   task_struct 保存
             每个进程之间都参与内核的调用,彼此之间不受影响。
             进程开销大(时间片轮转,开销和加载)
  线程: 
           线程是cpu的最小调度单位。
           同一个进程可以有多个线程,但都共享同一个地址空间。
            也称之为轻量级的进程(linux没办法区分进程和线程)
   特点: 大大提高了任务的切换效率。
   使用进程的哪些资源:
         可执行的指令。(代码)
         静态数据(全局变量,常量,静态变量);
         进程中的文件描述符
         当前的工作目录
         用户id  用户组id
 线程的唯一标志:PCB
         线程id
         堆栈
         优先级
         线程的状态和属性

コーディング手順

 1. 创建线程
  2.线程的分离
  3.线程的处理
  4.线程的退出

プロセススレッド学習5日目

スレッドの作成

#include <pthread.h>
関数プロトタイプ: int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg); 関数パラメータ: スレッド thread オブジェクト、スレッド ID 値
attr
Thread属性 NULL
start_routine スレッド処理関数は、スレッドが作成されると、自動的にスレッド処理関数にジャンプします。
arg スレッド コールバック関数に渡されるパラメータ パラメータがない場合、NULL戻り値:成功
した場合は 0 を返し、失敗した場合は -1 を返します。
: スレッドを作成します
注: コンパイル中に -pthread を追加します

スレッドの終了

   函数原型:void pthread_exit(void *retval);
   函数参数:retval 退出码,可以被主线程获取到,pthread_join
   函数作用:退出线程
   函数返回值: 无

スレッドに参加する

#include <pthread.h>
関数プロトタイプ: int pthread_join(pthread_t thread, void **retval);
関数関数: メインスレッドはサブスレッドの終了を待ち、スレッド記述子を解放します
関数パラメータ: thread thread id
retval Secondaryポインタ、スレッドを受け入れます 終了の終了コード。(通常、これは第 1 レベルのポインターのアドレス、つまり受信アドレスです)
戻り値: 成功した場合は 0 を返し、失敗した場合はエラー errno を返します。

スレッドの分離:

  当线程分离后,主线程不需要等待子线程结束,不需要join也会释放子线程pcb,理解成线程的托管。分离后的线程由1号线程,也就是init线程托管。
  编码步骤:(创建前分离)

1 スレッドの初期化

関数プロトタイプ: int pthread_attr_init(pthread_attr_t *attr);
     作用: 对线程进行初始化,获得状态信息。通过(pthread_attr_t 获得 
     函数参数:attr  传出参数,传入结构体地址,会得到状态信息
      返回值: 成功返回0  失败返回错误码。

2. 糸分離設定(分離状態の取得)

     函数原型:int pthread_attr_setdetachstate (pthread_attr_t *__attr,int __detachstate)
     函数作用:用来设置线程分离
     函数参数: attr 从init函数的第一个参数来。
                       __detachstate  设置或者获取分离状态
                        PTHREAD_CREATE_DETACHED    分离            
                        PTHREAD_CREATE_JOINABLE      
     返回值:成功返回0  失败返回错误码

関数プロトタイプ: int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);

      函数作用:获取线程的分离状态
      函数参数:  attr 从init函数的第一个参数来。
                       __detachstate  获取分离状态,是传出参数。
      返回值:成功返回0  失败返回错误码
         
  
   创建后分离,填入线程id后 ,此线程就变成了分离线程

関数プロトタイプ: int pthread_detach(pthread_t thread);

   头文件:  #include <pthread.h>
   函数作用: 对线程进行创建后分离。

相互排他ロック: 複数のプロセスが重要なリソースに同時にアクセスした場合、重要なリソースがロックされる可能性があり、ロックを取得したスレッドが実行され、ロックを取得しなかったスレッドは待機します。

ステップ:

  1.先对互斥锁初始化
   2.加锁操作
   3.数据处理
   4.解锁操作
   5.销毁互斥锁

関数数原型:int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);

   函数作用: 对互斥锁进行初始化
   函数参数:mutex 互斥锁对象 或者说互斥锁id
                   mutexattr 属性 NULL
    返回值:如果成功返回0 失败返回错误码 errno

関数プロトタイプ: int pthread_mutex_lock(pthread_mutex_t *mutex);

    函数参数: mutex   是init的第一个参数
    作用: 对互斥锁加锁。其他线程没法在加锁。
    返回值:如果成功返回0 失败返回错误码 errno

関数プロトタイプ: int pthread_mutex_trylock(pthread_mutex_t *mutex);

    作用:尝试枷锁,如果没有锁则直接返回,不等待
    返回值:如果成功返回0 失败返回错误码 errno

関数プロトタイプ: int pthread_mutex_unlock(pthread_mutex_t *mutex);

   作用: 对互斥锁解锁操作
   函数参数:  mutex   是init的第一个参数
    返回值:如果成功返回0 失败返回错误码 errno

関数プロトタイプ: int pthread_mutex_destroy(pthread_mutex_t *mutex);

    作       用: 对互斥锁解锁操作
    函数参数:  mutex   是init的第一个参数
    返  回 值:如果成功返回0 失败返回错误码 errno

信号量:

  步骤:
  1.信号量的初始化
  2.pv操作
  3.销毁信号量


   #include <semaphore.h>

関数プロトタイプ: int sem_init(sem_t *sem, int pshared, unsigned int value);

   函数参数:sem 信号量的对象(传入地址,函数中会修改指针指向的空间值)
                    pshared   如果是0 表示线程   如果是非0表示进程。(可以处理进程和线程)
                    value  信号量的初值。
   函数作用:初始化信号量
   返  回 值:成功返回0 失败返回-1

     #include <semaphore.h>

関数プロトタイプ: int sem_wait(sem_t *sem);

    函数参数:sem    信号量对象
    函数作用: 是信号量的p操作,信号量-1,占用资源
    返回值: 如果成功返回0  失败-1

          #include <semaphore.h>

関数プロトタイプ: int sem_post(sem_t *sem);

    函数参数: sem   信号量对象   sem_init的第一个参数
   返回值:如果成功返回0  失败-1
  函数作用: 对信号量进行v操作,是否资源,信号量+1

Guess you like

Origin blog.csdn.net/qq_52531759/article/details/127182015