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 オブジェクトを作成する方法

推薦する

Node.js は、異なるリクエストパスに応じて異なるデータを返します。

目次1. 異なるリクエストパスに応じて異なるデータを返す方法を学びます。 2. 送信データ: データ...

WeChatアプレットのオーディオコンポーネントがiOSで再生できない問題の解決策

解決策:クリック イベントをオーディオ コンポーネントにバインドし、再生メソッドと一時停止メソッドを...

CSSはクーポンスタイルを実装するために放射状グラデーションを使用します

この記事では、CSS で放射状グラデーションを使用して、次の図に示すクーポン スタイルの効果を実現す...

IDEA2020.1.2 Webプロジェクトの作成とTomcatの設定に関する詳細なチュートリアル

この記事は、IDEA で Web プロジェクトを作成し、Tomcat を構成する方法についての統合記...

MySQL 文字列分割操作 (区切り文字を含む文字列のインターセプション)

区切り文字なしの文字列抽出質問の要件データベース内のフィールド値:実装効果: 1行のデータを複数行に...

Vueはパーセンテージバー効果を実現します

この記事では、パーセンテージバーを実現するためのVueの具体的なコードを参考までに共有します。具体的...

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

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

HTML の基礎: HTML コンテンツの詳細

まずは本体から始めましょう:ウェブページを閲覧するとき、最初に目に留まるのは通常、ページの背景です。...

nginx で複数の仮想ホストを設定する方法の例

nginx で仮想ホスト vhost を設定すると非常に便利です。 nginx設定ファイルnginx...

WebページでjQueryを参照する方法

CDN(コンテンツ配信ネットワーク)を通じて参照できます。 jQuery は Google と Mi...

Google の新しい UI から学べること (画像とテキスト)

2011 年に最も顕著なウェブサイトの変更は、一連の製品に新しいユーザー インターフェースを導入した...

Linux での JDK と Tomcat のアップロードと設定に関する詳細なチュートリアル

準備1. 仮想マシンを起動する2. gitツールルートアカウントでログインルートアカウントを使用して...

MySQL の効率的なクエリの左結合とグループ化 (プラス インデックス)

mysql 効率的なクエリMySQL は、左結合の速度を上げるために group by を犠牲にし...

スケルトンスクリーン効果を実現する CSS

ネットワーク データを読み込むときは、ユーザー エクスペリエンスを向上させるために、通常は円形の読み...

Vue を使用してパブリック アカウントの Web ページを開発する方法

目次プロジェクトの背景始めるvue-cliでプロジェクトを作成するモバイル適応についてnormali...