スレッド間で共有されるリソースは何ですか?


264

最近、インタビューでプロセスとスレッドの違いは何ですかと質問されました。本当に、私は答えを知りませんでした。私は少し考えて、非常に奇妙な答えを出しました。

スレッドは同じメモリを共有しますが、プロセスは共有しません。これに答えた後、インタビュアーは私に邪悪な笑顔を与え、私に次の質問をしました

Q. プログラムが分割されるセグメントを知っていますか?

私の答え:はい(簡単なものだと思いました)スタック、データ、コード、ヒープ

Q. では、スレッドを共有するセグメントを教えてください。

私はこれに答えることができず、それらすべてを言うことになりました。

プロセスとスレッドの違いについて、誰でも正確で印象的な答えを提示できますか?


9
スレッドは同じ仮想アドレス空間を共有しますが、プロセスは共有しません。
Benoit

回答:


177

あなたはかなり正しいですが、スレッドはスタックを除くすべてのセグメント共有します。スレッドには独立した呼び出しスタックがありますが、他のスレッドスタックのメモリは引き続きアクセス可能であり、理論的には他のスレッドのローカルスタックフレームでメモリへのポインターを保持できます(ただし、そのメモリを配置するより良い場所を見つける必要があります!)。


27
興味深いのは、スレッドに独立した呼び出しスタックがあっても、他のスタックのメモリには引き続きアクセスできることです。
Karthik Balaguru、2014年

1
はい-スレッド間で他のスタックのメモリにアクセスすることが許容されるかどうか疑問に思っていますか?割り当て解除されたスタックを参照しようとしているのではないと確信している限り、それに問題があると思いますか?
bph 2018

2
@bph:別のスレッドのスタックメモリにアクセスすることは可能ですが、優れたソフトウェアエンジニアリングの慣行のために、アクセスすることは許容できるとは言えません。
グレッグヒューギル2018

1
他のスレッドのスタックへのアクセス、特に書き込みは、いくつかのガベージコレクター実装で混乱します。ただし、これはGC実装の​​障害として正当化される可能性があります。
yyny

56

ウィキペディアから(インタビュアー:Pにとって本当に良い答えになると思います)

スレッドは、以下の点で従来のマルチタスクオペレーティングシステムプロセスとは異なります。

  • プロセスは通常独立していますが、スレッドはプロセスのサブセットとして存在します
  • プロセスはかなりの状態情報を保持しますが、プロセス内の複数のスレッドは状態やメモリなどのリソースを共有します
  • プロセスは個別のアドレス空間を持っているが、スレッドはアドレス空間を共有している
  • プロセスは、システム提供のプロセス間通信メカニズムを介してのみ相互作用します。
  • 同じプロセス内のスレッド間のコンテキスト切り替えは、通常、プロセス間のコンテキスト切り替えよりも高速です。

2
上記のポイント2について:スレッドの場合、CPUもコンテキストを維持します。
ジャック

49

本当に指摘する必要があるのは、この質問には実際には2つの側面があるということです。理論的な側面と実装の側面です。

まず、理論的な側面を見てみましょう。プロセスとスレッドの違いとそれらの間で共有されるものを理解するには、プロセスが概念的に何であるかを理解する必要があります。

私たちは、セクションから、次のしている2.2.2古典スレッドモデル現代的なオペレーティングシステムの3Eタネンバウムによって:

プロセスモデルは、リソースのグループ化と実行という2つの独立した概念に基づいています。それらを分離すると便利な場合があります。ここがスレッドの出番です...

彼は続けます:

プロセスを見る1つの方法は、関連するリソースをグループ化する方法であるということです。プロセスには、プログラムテキストとデータ、およびその他のリソースを含むアドレススペースがあります。これらのリソースには、開いているファイル、子プロセス、保留中のアラーム、シグナルハンドラー、アカウンティング情報などが含まれます。それらをプロセスの形でまとめることにより、より簡単に管理できます。プロセスが持つもう1つの概念は、実行のスレッドであり、通常は単にスレッドに短縮されます。スレッドには、次に実行する命令を追跡するプログラムカウンターがあります。現在の作業変数を保持するレジスタがあります。実行履歴を含むスタックがあり、呼び出されたがまだ返されていないプロシージャごとに1つのフレームがあります。スレッドは何らかのプロセスで実行する必要がありますが、スレッドとそのプロセスは異なる概念であり、個別に処理できます。プロセスは、リソースをグループ化するために使用されます。スレッドは、CPUでの実行がスケジュールされているエンティティです。

さらに下には、次の表があります。

Per process items             | Per thread items
------------------------------|-----------------
Address space                 | Program counter
Global variables              | Registers
Open files                    | Stack
Child processes               | State
Pending alarms                |
Signals and signal handlers   |
Accounting information        |

上記は、スレッドが機能するために必要なものです。他の人が指摘したように、セグメントなどはOSに依存する実装の詳細です。


2
これは素晴らしい説明です。しかし、おそらく、「回答」と見なされるために何とか質問に背を接続する必要があります
catalyst294の

テーブルに関して、プログラムカウンターはレジスターではありませんか?そして、レジスタの値にキャプチャされたスレッドの「状態」?彼らが実行するコードへのポインター(プロセステキストへのポインター)もあり
ません

29

OSの実装に完全に依存していることをインタビュアーに伝えます。

たとえば、Windows x86について考えてみます。コードとデータの2つのセグメント[1] しかありません。また、どちらも2GB(リニア、ユーザー)アドレス空間全体にマッピングされています。Base = 0、Limit = 2GB。彼らはそれを作ったでしょうが、x86はセグメントが読み取り/書き込みと実行の両方になることを許可していません。したがって、2つを作成し、CSがコード記述子を指すように設定し、残り(DS、ES、SSなど)が他を指すように設定しました[2]。しかし、両方とも同じものを指しています!

あなたにインタビューした人は彼/彼女が述べていないという隠された仮定をしました、そしてそれは引っ張る愚かなトリックです。

それで

Q.では、どのセグメントスレッドシェアを教えてください。

セグメントは、少なくともWindowsでは、問題とは無関係です。スレッドはアドレス空間全体を共有します。スタックセグメントはSSが1つだけあり、それはDS、ES、およびCSが行うものとまったく同じものを指します[2]。すなわち全体血まみれのユーザ空間を。0〜2 GB。もちろん、スレッドが1つのスタックしか持たないという意味ではありません。当然、それぞれに独自のスタックがありますが、x86セグメントはこの目的には使用されません。

多分* nixは何か違うことをします。知るか。質問の根拠となった前提が破られました。


  1. 少なくともユーザー空間では。
  2. からntsd notepadcs=001b ss=0023 ds=0023 es=0023

1
はい...セグメントは、OSとコンパイラ/リンカーによって異なります。DATAセグメントとは別のBSSセグメントが存在する場合があります。時々RODATA(読み取り専用とマークされたページにある定数文字列のようなデータ)があります。一部のシステムでは、DATAをSMALL DATA(ベース+ 16ビットオフセットからアクセス可能)と(FAR)DATA(アクセスに32ビットオフセットが必要)に分割することもあります。これは、スレッドごとに生成される余分なTLS DATA(スレッドローカルストア)セグメントが存在することも可能です
Adisak

5
あ、違う!セグメントとセクションを混同しています!セクションとは、リンカーがモジュールをパーツ(データ、rdata、テキスト、bssなど)に分割する方法です。しかし、私はintel / amd x86ハードウェアで指定されているセグメントについて話している。コンパイラ/リンカーとはまったく関係ありません。それが理にかなっていると思います。
Alex Budovski、2009年

ただし、Adisakはスレッドローカルストアについては適切です。これはスレッド専用であり、共有されません。私はWindows OSを知っていますが、他のOSはわかりません。
ジャック

20

一般に、スレッドは軽量プロセスと呼ばれます。メモリを3つのセクションに分割すると、コード、データ、スタックになります。すべてのプロセスには独自のコード、データ、スタックセクションがあり、このコンテキストにより、切り替え時間が少し長くなります。コンテキストの切り替え時間を短縮するために、データとコードセグメントを他のスレッド/プロセスと共有するスレッドの概念が考案され、独自のスタックセグメントがあります。


ヒープを忘れました。ヒープは、私が間違っていなければ、スレッド間で共有する必要があります
Phate

20

プロセスには、コード、データ、ヒープ、スタックのセグメントがあります。現在、スレッドORスレッドの命令ポインタ(IP)は、プロセスのコードセグメントを指しています。データセグメントとヒープセグメントは、すべてのスレッドで共有されます。スタック領域はどうですか?実際にスタック領域とは何ですか?その領域は、スレッドが使用するためにプロセスによって作成されます...スタックはヒープなどよりもはるかに高速に使用できるためです。プロセスのスタック領域はスレッド間で分割されます。つまり、3つのスレッドがある場合、プロセスのスタック領域は3つの部分に分割され、それぞれが3つのスレッドに割り当てられます。つまり、各スレッドに独自のスタックがあると言えば、そのスタックは実際には各スレッドに割り当てられたプロセススタック領域の一部です。スレッドが実行を終了すると、スレッドのスタックはプロセスによって回収されます。実際には、プロセスのスタックがスレッド間で分割されるだけでなく、SP、PC、状態レジスタなど、スレッドが使用するすべてのレジスタセットは、プロセスのレジスタです。したがって、共有に関しては、コード、データ、ヒープ領域が共有され、スタック領域はスレッド間で分割されます。


13

スレッドはコードとデータセグメント、およびヒープを共有しますが、スタックは共有しません。


11
「スタック内のデータにアクセスできる」とスタックの共有には違いがあります。これらのスレッドには、メソッドを呼び出すときにプッシュおよびポップされる独自のスタックがあります。
Kevin Peterson

2
どちらも同じように有効なビューです。はい、スレッドとスタックは1対1で対応しているという意味で、すべてのスレッドには独自のスタックがあり、各スレッドは独自のスタック使用のために使用するスペースを持っています。ただし、これらは完全に共有されたプロセスリソースでもあり、必要に応じて、どのスレッドも他のスレッドのスタックに独自のスレッドと同じくらい簡単にアクセスできます。
David Schwartz、

@DavidSchwartz、あなたのポイントを以下のように要約できますか:すべてのスレッドには独自のスタックがあり、スタックは2つの部分で構成されます-プロセスがマルチスレッド化される前にスレッド間で共有される最初の部分と、所有しているスレッドが実行中です。同意しますか?
FaceBro、2015

2
@nextTide 2つの部分はありません。スタックは共有され、期間です。各スレッドには独自のスタックがありますが、それらも共有されます。おそらく良いアナロジーは、あなたとあなたの妻がそれぞれ車を持っているが、いつでも好きなときにお互いの車を使うことができる場合です。
David Schwartz、

5

スレッドはデータとコードを共有しますが、プロセスは共有しません。スタックは両方で共有されません。

プロセスはメモリを共有することもできます。より正確には、たとえばの後のコードですFork()が、これは実装の詳細と(オペレーティングシステムの)最適化です。複数のプロセスで共有されるコードは、コードへの最初の書き込み時に(うまくいけば)複製されます-これは、コピーオンライトとして知られています。スレッドのコードの正確なセマンティクスについてはわかりませんが、共有コードを想定しています。

           プロセススレッド

   スタックプライベートプライベート
   データプライベート共有
   コードプライベート1   共有2

1コードは論理的にプライベートですが、パフォーマンス上の理由から共有される場合があります。 2 100%よくわかりません。


ほとんどのアーキテクチャでは、データとは異なり、コードセグメント(テキストセグメント)はほとんど常に読み取り専用です。
ホルヘコルドバ、

4

スレッドはすべてを共有します [1]。プロセス全体に1つのアドレススペースがあります。

各スレッドには独自のスタックとレジスタがありますが、すべてのスレッドのスタックは共有アドレス空間に表示されます。

あるスレッドがスタックにオブジェクトを割り当て、そのアドレスを別のスレッドに送信すると、どちらのスレッドもそのオブジェクトに同等にアクセスできます。


実際、もっと広い問題に気づきました。「セグメント」という2つの使い方を混同していると思います。

実行可能ファイル(ELFなど)のファイル形式には、コンパイル済みコード(テキスト)、初期化されたデータ、リンカーシンボル、デバッグ情報などを含む、セグメントと呼ばれる可能性のある別個のセクションがあります。ヒープまたはスタックセグメントはありません。ここでは、これらは実行時のみの構成であるためです。

これらのバイナリファイルセグメントは、異なるアクセス許可(たとえば、コード/テキストの読み取り専用実行可能ファイル、および初期化されたデータのコピーオンライト非実行可能ファイル)を使用して、プロセスアドレス空間に個別にマッピングできます。

このアドレススペースの領域は、ヒープ割り当てやスレッドスタックなど、さまざまな目的で使用されます(言語ランタイムライブラリによって強制されます)。ただし、これは単なるメモリであり、仮想8086モードで実行している場合を除いて、おそらくセグメント化されません。各スレッドのスタックは、スレッドの作成時に割り当てられたメモリのチャンクであり、現在のスタックトップアドレスはスタックポインターレジスタに格納され、各スレッドは独自のスタックポインターを他のレジスタと共に保持します。


[1]はい、わかりました:シグナルマスク、TSS / TSDなど。ただし、マップされたすべてのプログラムセグメントを含むアドレス空間は引き続き共有されます。


3

x86フレームワークでは、多くのセグメント(最大2 ^ 16-1)を分割できます。ASMディレクティブSEGMENT / ENDSはこれを許可し、演算子SEGおよびOFFSETはセグメントレジスタの初期化を許可します。CS:IPは通常ローダーによって初期化されますが、DS、ES、SSの場合、アプリケーションが初期化を担当します。多くの環境では、.code、.data、.bss、.stackなどのいわゆる「単純化されたセグメント定義」が可能であり、「メモリモデル」(小、大、コンパクトなど)にもよりますが、ローダーはセグメントレジスタを初期化しますそれに応じて。通常、.data、.bss、.stack、およびその他の通常のセグメント(20年前からこれを行っていないため、すべてを覚えていません)は1つのグループにグループ化されています。そのため、通常、DS、ES、およびSSは、同じ領域ですが、これは物事を単純化するためだけです。

一般に、すべてのセグメントレジスタは実行時に異なる値を持つことができます。したがって、インタビューの質問は正しかった:CODE、DATA、およびSTACKのどれがスレッド間で共有されるか。ヒープ管理は別のことです-それは単にOSへの一連の呼び出しです。しかし、組み込みシステムのように、OSがまったくない場合はどうなりますか?コードに新規/削除を含めることはできますか?

若い人たちへの私のアドバイス-いくつかの良いアセンブリプログラミングの本を読んでください。大学のカリキュラムはこの点でかなり貧弱なようです。


2

グローバルメモリに加えて、スレッドは他の多くの属性も共有します(つまり、これらの属性はスレッドに固有ではなく、プロセスに対してグローバルです)。これらの属性には次のものがあります。

  • プロセスIDと親プロセスID。
  • プロセスグループIDとセッションID。
  • 制御端末;
  • 資格情報(ユーザーIDとグループID)を処理します。
  • ファイル記述子を開く。
  • を使用して作成されたレコードロック fcntl();
  • 信号処理;
  • ファイルシステム関連の情報:umask、現在の作業ディレクトリ、ルートディレクトリ。
  • インターバルタイマー(setitimer())およびPOSIXタイマー(timer_create());
  • System Vセマフォundo(semadj)値(47.8節);
  • リソース制限;
  • 消費されたCPU時間(によって返されるtimes())。
  • 消費されるリソース(によって返されるgetrusage())。そして
  • nice値(setpriority()およびで設定nice())。

各スレッドで異なる属性には、次のものがあります。

  • スレッドID(セクション29.5);
  • シグナルマスク;
  • スレッド固有のデータ(セクション31.3)。
  • 代替信号スタック(sigaltstack());
  • errno変数。
  • 浮動小数点環境(を参照fenv(3)
  • リアルタイムのスケジューリングポリシーと優先度(セクション35.2および35.3)。
  • CPUアフィニティ(Linux固有、セクション35.4で説明);
  • 機能(Linux固有、第39章で説明); そして
  • スタック(ローカル変数と関数呼び出しリンケージ情報)。

抜粋:The Linux Programming Interface:A Linux and UNIX System Programming Handbook、Michael Kerrisk、page 619


0

スレッドはヒープを共有します(スレッド固有のヒープに関する調査があります)が、現在の実装はヒープを共有しています。(そしてもちろんコード)


0

プロセスでは、スレッドが独自のスタックを持っている間、すべてのスレッドがヒープメモリなどのシステムリソースを共有します。

したがって、ansは、すべてのスレッドがプロセスのために共有するヒープメモリである必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.