Linux マルチスレッドにおけるフォークとミューテックス ロック プロセスの例

Linux マルチスレッドにおけるフォークとミューテックス ロック プロセスの例

質問:

このような問題があります。マルチスレッド プログラムで子プロセスを作成し、子線程子進程グローバル変数のロックを取得させ、出力子スレッドがロックを取得してロックを解除し、子プロセスがロックを取得してロックを解除します。

1. 最初の試み

コード:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/wait.h>

pthread_mutex_t ミューテックス;

void* 関数(void* 引数)
{
	pthread_mutex_lock(&mutex);	
	printf("fun get lock\n");
	睡眠(3);

	pthread_mutex_unlock(&mutex);
	printf("fun unlock\n");
}
int メイン()
{
	pthread_mutex_init(&mutex, NULL);
	pthread_t ID;
	pthread_create(&id, NULL, fun, NULL);
	
	睡眠(1);
	pid_t pid = fork();
	(pid == -1)の場合
	{
		perror("フォークエラー");
		-1 を返します。
	} 

	pid == 0 の場合
	{
		pthread_mutex_lock(&mutex);	
		printf("子がロックを取得\n");
		睡眠(3);
		
		pthread_mutex_unlock(&mutex);
		printf("子のロック解除\n");
		終了(0);
	}
	
	待機(NULL);

	pthread_mutex_destroy(&mutex);
	printf("メイン終了\n");
	0を返します。
}

推測結果:

考えを整理しましょう:

グローバルロックを作成して初期化する
メインスレッドはロックを取得するために子スレッドを作成します。メインスレッドは 1 秒間スリープし、子スレッドがロックを取得してロックします。
子スレッドは3秒間スリープし、unlock funを出力し、子スレッドは終了します。
メインスレッドがフォークを開始し、子プロセスがロックを取得し、子ロックを出力する
子プロセスのロック解除出力 子のロック解除
親プロセスのメインスレッドは子プロセスが終了するのを待ち、最後にロックを破棄してmain overを出力する。
それで…正しいコードにすぐにアクセスしましょう! ! !

2. 合理的な分析

残念ながら、答えは間違っています。 ! !

我們先來康康運行結果:正常輸出了子線程的內容,但是。。。。卡住了?沒錯阻塞了。。

ここに画像の説明を挿入

再度分析します:

ブロック? ?ロックを取得するときに子プロセスがブロックされる可能性がありますか?または、親プロセスが子プロセスを待ってブロックされていますか?
つまり、両方の場所がブロックされ、子プロセスはロックを取得するときにブロックされ、親プロセスがブロックされます。
検証してください! !

ここに画像の説明を挿入

したがって、プログラムは 2 か所でブロックされます。子プロセスはロックを取得するときにブロックされ、その結果、親プロセスがブロックされます。

3. 問題解決

實際上,我們子線程在獲取這把鎖并加鎖后睡眠3秒,主線程睡眠1秒,在主線程1秒睡眠結束后,開始執行fork,此時的子線程還未解鎖正處于睡眠狀態,fork過程中,會直接復制父進程的所有資源(**包括這把鎖、鎖的狀態**),沒錯

就是有兩把鎖。此時子線程進行了加鎖的狀態,所以子線程復制的鎖也是加鎖狀態。所以子線程會正常退出,而子進程會因為拿到加鎖的鎖而阻塞,父進程wait因為子進程阻塞而阻塞;

(1) pthread_join()の使用

フォークする前に pthread_join() を使用します。子スレッドが終了する前にメインスレッドはブロックされ、子スレッドが終了するのを待ってからフォークします。このとき、子プロセスが取得したロックは解除されます。

コード:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/wait.h>

pthread_mutex_t ミューテックス;

void* 関数(void* 引数)
{
	pthread_mutex_lock(&mutex);	
	printf("fun get lock\n");
	睡眠(3);

	pthread_mutex_unlock(&mutex);
	printf("fun unlock\n");
}
int メイン()
{
	pthread_mutex_init(&mutex, NULL);
	pthread_t ID;
	pthread_create(&id, NULL, fun, NULL);
	pthread_join(id, NULL);
	
	睡眠(1);

	pid_t pid = fork();
	(pid == -1)の場合
	{
		perror("フォークエラー");
		-1 を返します。
	} 

	pid == 0 の場合
	{
		pthread_mutex_lock(&mutex);	
		printf("子がロックを取得\n");
		睡眠(3);

		pthread_mutex_unlock(&mutex);
		printf("子のロック解除\n");
		終了(0);
	}
	
	待機(NULL);

	pthread_mutex_destroy(&mutex);
	printf("メイン終了\n");
	0を返します。
}

結果:

ここに画像の説明を挿入

(2)phread_atfork()を使ってフォーク前の判定を登録する

ヘッダーファイル: pthread.h

int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));

prepare: この関数はforkが実行される前に呼び出されます

親: 親プロセスはフォークが実行された後にこの関数を呼び出します

child: forkが実行された後、子プロセスはこの関数を呼び出します

戻り値: 成功した場合は 0、失敗した場合はエラーコード

コード:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/wait.h>

pthread_mutex_t ミューテックス;

void prepare_fun(void)
{
	pthread_mutex_lock(&mutex);
}

void 親関数(void)
{
	pthread_mutex_unlock(&mutex);
}

void 子関数()
{
	pthread_mutex_unlock(&mutex);
}

void* 関数(void* 引数)
{
	pthread_mutex_lock(&mutex);	
	printf("fun get lock\n");
	睡眠(3);

	pthread_mutex_unlock(&mutex);
	printf("fun unlock\n");
}

int メイン()
{
	
	pthread_mutex_init(&mutex, NULL);
	pthread_t ID;
	pthread_atfork(準備関数、親関数、子関数);
	pthread_create(&id, NULL, fun, NULL);
	
	睡眠(1);

	pid_t pid = fork();
	(pid == -1)の場合
	{
		perror("フォークエラー");
		-1 を返します。
	} 

	pid == 0 の場合
	{
		pthread_mutex_lock(&mutex);	
		printf("子がロックを取得\n");
		睡眠(3);

		pthread_mutex_unlock(&mutex);
		printf("子のロック解除\n");
		終了(0);
	}
	
	待機(NULL);

	pthread_mutex_destroy(&mutex);
	printf("メイン終了\n");
	0を返します。
}

結果:

ここに画像の説明を挿入

Linux マルチスレッドのフォークとミューテックス プロセスの例に関するこの記事はこれで終わりです。Linux マルチスレッドのフォークとミューテックスに関する関連コンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Pythonのガベージコレクションの仕組みの詳しい説明
  • Python言語開発ガベージコレクションメカニズム原理チュートリアル
  • Python ガベージコレクション機構の原理分析
  • Python のガベージコレクションはどのように実装されていますか?
  • Linux でのマルチスレッドにおけるフォークの紹介
  • Python ガベージコレクションと Linux フォーク

<<:  CSS 線形グラデーション凹型長方形遷移効果の実装

>>:  JavaScript で動的な QML オブジェクトを作成する方法

推薦する

Nginx Webサーバーのサンプルコードの設定方法の詳細な説明

概要今日は主に、NGINX を Web サーバーとして設定する方法を共有します。内容は次のとおりです...

ボックスモデルのサイズの詳細な説明は、パディング、マージン、境界の値によって異なります。

ボックス モデルは、要素ボックスの幅と高さ、パディング、境界線、余白のサイズを指定します。境界線の内...

HTML テーブル マークアップ チュートリアル (6): 暗い境界線の色属性 BORDERCOLORDARK

表では、右下の境界線の色を個別に定義したり、セルの左上の境界線の色を定義したりできます。これら 2 ...

Linux の文字端末でマウスを使って赤い四角形を移動する方法

すべてがファイルです! UNIX はすでにそれを言っています。エリック・レイモンドはこう言いました。...

nginxリバースプロキシのyum設定の詳細な手順

パート0 背景社内のイントラネットサーバーは直接インターネットにアクセスすることはできませんが、外部...

HTMLの基礎知識:ウェブページの基礎知識

HTML は Hypertext Markup Language の略です。これは、実際のプレゼンテ...

MySQLで現在の時間間隔の前日のデータをクエリする

1. 背景実際のプロジェクトでは、分散スケジュールされたタスク実行の状況に遭遇することがあります。ス...

Docker Compose のインストールと使用手順

目次1. Docker Compose とは何ですか? 2. Docker Composeのインスト...

Docker での Redis 接続の急増をトラブルシューティングした実践的な記録

土曜日、本番サーバー上の Redis サーバーが利用できなくなり、エラー メッセージは次のようになり...

EclipseのプロジェクトをTomcatに追加できない問題を解決する方法

1. プロジェクトを右クリックしてプロパティを選択します2. プロジェクトファセットをクリック3. ...

Linux ファイアウォールを設定してポート 80 と 3306 を開く方法

ポート80も設定されています。まずファイアウォール設定ファイルを入力しますシェル># vim ...

CentOS に MySQL をインストールしてリモート アクセスを設定する方法

1. MySQLリポジトリソースをダウンロードする$ wget http://repo.mysql....

MySQL Binlog ログの読み取り時によくある 3 つのエラー

1. mysqlbinlog: [エラー] 不明な変数 'default-character...

MySQL のフィールドに一意のインデックスを追加および削除する方法

1. PRIMARY KEY(主キーインデックス)を追加するmysql>ALTER TABLE...

フレックスとポジションの互換性の詳細な説明マイニングノート

今日は、すべてのブラウザ (主に IE 9 以上と Chrome) と互換性のある自分のホームページ...