質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1310閲覧

pthread と python threading, goroutine の違いとスレッドの実体についての疑問

akiyama3284pga

総合スコア186

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

2クリップ

投稿2023/01/23 01:49

編集2023/01/27 21:13

イメージ説明

疑問1.
python や go のスレッドはユーザレベルの、完全にユーザ空間で完了するものだと思います。(プロセスコンティションスコープであり、内部でcloneは使用しない。)
pthreadは内部でcloneを呼ぶそうなので、これはカーネルスレッドからすべて生成する、カーネルレベルスレッディング用のライブラリ(システムコンティションスコープ)と考えてもよいのでしょうか?
つまり、プロセス2の状態は、1つ目ののスレッドからpthread_create()か、独自にclone()した状態

疑問2.
ユーザスレッド ---- LWP ---- カーネルスレッド
という構図ができると思うのですが、例えば図のプロセス1の場合、結局その実体は"いくつ""どこに""何というものとして"できるのでしょうか?
自分は、カーネルスレッド毎に実体ができると考えています。なので、プロセス1では合計1つの実体ができると考えます。
そしてその実体は、task_structだと考えます。(ユーザスレッドはその実体を共有する。)
なのでプロセス2では、合計2つのtask_structが生成されると思います。

今後スレッドをメインにプログラミングしていく際に、このあたりの理解から使用言語を絞りたいと考えております。

--追記
python threading は、試してみたところ、

aa 9992 9962 9992 0 3 11:48 pts/0 00:00:00 python3 thre.py aa 9992 9962 9993 0 3 11:48 pts/0 00:00:00 python3 thre.py aa 9992 9962 9994 0 3 11:48 pts/0 00:00:00 python3 thre.py

のように各スレッド(mainとmianから派生したスレッド*2)にLWP番号が振られていましたので、カーネルレベルのスレッディングだということがわかりました。
機能的にはpthreadと同等という感じでしょうか。

--追記2
イメージ説明

--追記3
pthreadライブラリには大きく3種類ほどあり、
1:1モデルを採用するLinux threads, NPTL(native posix thread library),
M:Nモデルを採用するNGPT(next generation posix thread)
という具合に分かれているようです。
つまり、本記事で自分が考えているpthreadは、NPTLのことです。

M:Nモデルは、複数のユーザスレッドを複数のLWP上で実行する、goroutineとNPTLを足したようなもののようですが、
これは理解が難しそうなので、とりあえずおいておきます...

PPIDが2のカーネルスレッドを、"カーネルデーモン"という呼び方ができるようなので、
LWPのことをカーネルスレッドとも呼べるので、その使い分けとして使うのもありだと思った。

あるスレッドについて、ユーザモードで実行中の場合、それをユーザスレッドと呼び、
カーネルモードで実行中の場合、それをLWP(またはカーネルスレッド)と呼ぶよう。
とにかくそのスレッドの実体は1つのtask_structであり、また、当然カーネルデーモンとは違い、個別のアドレス空間を持つ。

カーネルからはLWPをプロセスと見るし、
ユーザからはスレッドの集合をプロセスと見る場合が多い。

--追記4
goroutine thread model
引用元
https://osmh.dev/posts/goroutines-under-the-hood
イメージ説明

--追記5
goroutine 現在の理解

goroutineをM:Nとして使う(NPTLと対比)⇓
イメージ説明

goroutineを1:Nとして使う⇓
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

quickquip

2023/01/23 03:07 編集

疑問1. の文が途中で終わっているように見えますが
quickquip

2023/01/23 03:57 編集

図の出所を書いた方がいい気がしました。それとも自分で描いた図でしょうか。 (追記されたように、LinuxのCPythonのスレッドが左な気はしないので……)
akiyama3284pga

2023/01/23 04:07

ありがとうございます。 図の方も修正いたしました。 自分の理解イメージで描いたもので、おかしな点等ありましたらご指摘頂ければ助かります。
quickquip

2023/01/23 12:26

図の右で、user threadとLWPとカーネルスレッドが別の箱になっているのはなぜか? (カーネルがマルチスレッドをサポートして以降だとLWPとスレッドは同じ概念では?) なぜuser threadと描いてある箱があるのか? 図の左で、"カーネルのスレッドを使わない"のなら、user threadとLWPが同じ概念になるのでは? あと、背景の user space と kernel space は何を示したものか? が分からなかったです。メモリ空間を想像しますが、だとしたら図の全体の意味が分からなくなります。 私はカーネルのシステムコールとかメモリ管理とかはあまり分からないので「go のスレッドはユーザレベルの、、完全にユーザ空間で完了するもの」「ユーザスレッド ---- LWP ---- カーネルスレッドという構図ができる」あたりの意味が取れませんでした。
akiyama3284pga

2023/01/23 13:34

例えば、下の2つの記事を中心に理解をしております。 https://docs.oracle.com/cd/E19683-01/816-3976/mtintro-72944/index.html https://en-m-wikipedia-org.translate.goog/wiki/Light-weight_process?_x_tr_sl=en&_x_tr_tl=ja&_x_tr_hl=ja&_x_tr_pto=sc 前者では、 "軽量プロセス (LWP) はユーザーレベルとカーネルレベルの橋渡しをします。各プロセスは、1 つ以上の LWP で構成されます。各 LWP は、1 つ以上のユーザースレッドを実行します " と説明されますが、 後者では、 "LWP は単一のカーネル スレッド上のユーザー空間で実行され.." とあります。 正直自分はユーザスレッドとLWPの違いといいますか、立ち位置がうまく解釈できていません。 LWP層が存在しない、カーネルスレッドとユーザスレッドが直接結合するモデルのOSもあるようなので、 LWP==ユーザスレッドというような理解で、ユーザレベルスレッディングをする場合にはLWPの存在を意識しないといけないくらいの認識でいいのかもしれません...(箱を書く必要性はなかった) あとは、これら記事で言われているカーネルスレッドとは、PPID2の[]で囲まれたものでは無いと思います。 記事によっては、その意味で以外カーネルスレッドとは呼ばないというようなスタンスのものも見受けれられます。 とすると、プロセス生成に伴って生成されるスケジューリング対象となるカーネルスレッドのことは何と呼べば差別化できるのか、このあたりもはっきりとできていません(もしくはこの意味でのカーネルスレッドをLWPと呼べばいいのか)...
quickquip

2023/01/23 14:36 編集

削除して回答にしました
guest

回答2

0

ベストアンサー

疑問1.
pthreadは内部でcloneを呼ぶそうなので、これはカーネルスレッドからすべて生成する、カーネルレベルスレッディング用のライブラリ(システムコンティションスコープ)と考えてもよいのでしょうか?

少なくとも、PthreadライブラリにNPTL実装を採用するLinux環境では YES です。
https://codebrowser.dev/glibc/glibc/nptl/pthread_create.c.html#285

つまり、プロセス2の状態は、1つ目ののスレッドからpthread_create()か、独自にclone()した状態

こちらの質問意図は良く分かりませんでした。
プロセス1とプロセス2が開始当初から別processというのであれば、Pthread的にもLinux LWP的にも互いに無関係のはずです。

疑問2.
ユーザスレッド ---- LWP ---- カーネルスレッド
という構図ができると

これらの用語を使って解釈するならば、下記のような対応関係になるはずです。

  • Python言語(CPython): ユーザスレッド と LWP=カーネルスレッド を1:1対応
  • Go言語: goroutine=ユーザスレッド と LWP=カーネルスレッド はN:M対応

余談:使用言語の選択理由が少し気になりました。

今後スレッドをメインにプログラミングしていく際に、このあたりの理解から使用言語を絞りたいと考えております。

実践的な観点でいえば、マルチスレッドプログラミングはプログラム設計・実装上の単なる手段に過ぎません。その言語が提供する抽象化/安全性レベル、サードパーティ含むライブラリ機能、開発チーム(個人)の習熟レベルを基に選ぶべきと思います。

カーネルレベルの対応関係まで気にするのであれば、Goのようなグリーンスレッドモデル言語やPythonのようなインタプリタ型言語は適切ではなく、C/C++/Rustなどの低レイヤ向けシステム・プログラミング言語が必要ではないでせしょうか?

投稿2023/01/27 01:11

yohhoy

総合スコア6189

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

akiyama3284pga

2023/01/27 01:45 編集

ありがとうございます。 すみません。"つまり、プロセス2の状態は、1つ目ののスレッドからpthread_create()か、独自にclone()した状態" という部分は、プロセス2のメインスレッドから、pthread_create()等を使用することで、プロセス2内でスレッドが一つ追加される様を伝えたかったのでございます。 ここが少し理解できないのですが、goroutineのようなスレッドライブラリは1(カーネルスレッド=LWP):多 となるように考えているのですが、ご回答ではそのようではない(M:N)とされています。 goroutineは機能としてpthreadのNGPTと同じ立ち位置というような認識でよろしいでしょうか? そうであれば、純なユーザ空間だけで完結するスレッドライブラリ(1:多)というのはあるのでしょうか... https://docs.oracle.com/cd/E19620-01/805-4031/6j3qv1oej/index.html https://osmh.dev/posts/goroutines-under-the-hood こういった記事を見ますと、goroutineは1:多のライブラリに属するものと考えてしまいます。 1:1 python threading, pthread(NPTL)... N:M(多対多) pthread(NGPT), goroutine, solaris thread... 1:多 ??? 余談の点につきましては、仰る通り、python等は色々な機能を抽象化していて細部が見辛いので最終的にはCでやっていきたいと考えております。
yohhoy

2023/01/27 02:39

> こういった記事を見ますと、goroutineは1:多のライブラリに属するものと考えてしまいます。 ある1つのgoroutineに着目すると複数OSスレッド上で実行される 1:多 関係ですが、プログラム中の複数goroutineは複数OSスレッドのいずれで実行されるという関係性が動的スイッチしうるため、M:Nモデルと解釈しています。 > 純なユーザ空間だけで完結するスレッドライブラリ(1:多)というのはあるのでしょうか... これらはの議論は、ユーザ(プログラマ)側からみえる実行主体(execution agent)と、ランタイム環境が提供するへ並行実行メカニズムとの対応関係に関する話です。 "スレッド"ライブラリという範疇からはそれてしまいますが、Go言語で GOMAXPROCS=1 を設定した状況や、OpenMPで OMP_NUM_THREADS=1 を設定した環境は 1:N モデルといえます。
akiyama3284pga

2023/01/27 04:40

すみません。理解が追い付かず... "ある1つのgoroutineに着目すると複数OSスレッド上で実行される 1:多 関係ですが、プログラム中の複数goroutineは複数OSスレッドのいずれで実行されるという関係性が動的スイッチしうる" という部分に関しまして、 OSスレッドというのをLWP(カーネルスレッド)と解釈しますと、 単一のOSスレッド(LWP)に対して、ユーザ空間で分岐させるのがユーザレベルスレッドライブラリと考えておりまして、それがgoroutineだと思っています(同プロセス内でも他のカーネルレベルのスレッドは無関係)。 複数のOSスレッドを使用するということは内部でclone()を使用してOSスレッドレベルから増やすということであり、これはカーネルレベルスレッディングを扱うライブラリ(NPTL等)ではないのでしょうか? NPTLはユーザレベルではスレッディングしないため、1:1 ユーザレベルでのみスレッディングするのが、1:多 NGPT等、上二つを同時に複雑に組み合わせるのが、M:N goroutineは1:NとN:M両方の機能を使い分けられるライブラリという認識でしょうか..
akiyama3284pga

2023/01/27 05:28 編集

すみません。何がおっしゃりたいのか、理解できたような気がします。 例えば、↓記事で、 https://qiita.com/riita10069/items/d448647b5f8b20c91264 "goroutineのスケジューラはm:nスレッドを用いているため、ユーザーモードのまま、goroutineの切り替えができ、コンテキストスイッチの必要が無いので、 スレッドの再スケジュールより低コストにスケジューリング可能です。" という文があり、それを読んで、カーネルレベルでの対応は1:Nだが、 goroutineが独自に実装しているユーザ空間でのスケジューラと、各goroutineにより生成されるものとの対応はM:Nを形成する。(一つ抽象度が高い部分での別次元の話) 自分はカーネルレベルでの対応について考えていたため、相違が出てしまったということだと思います。 それで、 "これらはの議論は、ユーザ(プログラマ)側からみえる実行主体(execution agent)と、ランタイム環境が提供するへ並行実行メカニズムとの対応関係に関する話です。" と言われていたのだと思いました。 整理しますと、 ■goroutineは、ユーザレベルスレッディングのライブラリ(LWPとの対応は1:N)ではあるが、"内部では"M:Nのような機構を疑似的に作り出しているライブラリである。 なので、 goroutineによるスレッディングは、それが作るスレッドのどれかがシステムコールを実行すると、他のスレッドもストップしてしまうというユーザレベルスレッディングライブラリが持つ弱点を、同様に持つ。 といった感じでしょうか..
yohhoy

2023/01/27 10:58 編集

> ■goroutineは、ユーザレベルスレッディングのライブラリ(LWPとの対応は1:N)ではあるが、"内部では"M:Nのような機構を疑似的に作り出しているライブラリである。 https://docs.oracle.com/cd/E19620-01/805-4031/6j3qv1oej/index.html うーん。私の理解するかぎり、そもそもスレッドモデルは上記サイトにあるように「A:ユーザから見えるスレッド」と「B:システムが提供する機構」をどう対応付けるかという観点です。 akiyama_pga さん解釈は、単に1つのA:goroutineがどのB:LWPに対応するかという局所的な話をされているように聞こえます。
yohhoy

2023/01/27 10:57

> goroutineによるスレッディングは、それが作るスレッドのどれかがシステムコールを実行すると、他のスレッドもストップしてしまうというユーザレベルスレッディングライブラリが持つ弱点を、同様に持つ。 ナイーブな「ユーザレベルスレッディングライブラリ」ではそのように振る舞いますが、Goランタイムはより高度な処理を行っています。 あるOSスレッド(=LWP)上で動作する goroutine がシステムコールを呼び出す場合、Goランタイムはそれを正しく検知し、同OSスレッド上で別のgoroutineを実行する仕組みを備えます。 https://zenn.dev/hsaki/books/golang-concurrency/viewer/internalcase
akiyama3284pga

2023/01/27 12:13 編集

資料のご提示をありがとうございます。 完全に自分の理解ミスがありました。 goroutineはM:Nを実現するスレッドライブラリだと腑に落ちました。 今の理解を図にしてアップロードいたしました。 ポイントは、 ・GOMAXPROCの値が2以上の場合は、goroutineライブラリは内部で動的にclone()を使用する。 ・プロセス内の各スレッド(LWP)内のgoroutine(G thread)をgoroutineスケジューラが移動(スイッチ)できるという点。これで、あるスレッドが内部のgoroutineによるシステムコールで該当スレッドがブロックされたら、待ちとなるはずのgoroutineは別の管轄のスレッドにスイッチすればよく、いわゆる1:多のスレッディングの弱点をカバーできる。 ・LWPの数を抑えることができ、つまりは1:1スレッディングの弱点(コンテキストスイッチの浪費)をカバーできる。 以上3点から、M:Nスレッディングの説明としてよくされています、1:1と多:1のいいとこどりができており、 これはどう考えてもgoroutineはカーネルレベルとユーザレベル両方を管理するM:Nスレッディングのライブラリだと判りました。 また、仰りましたとおり、GOMAXPROCは使用する論理CPU数(=LPW)を指定するフラグであり、これを1にすれば1:多のスレッディング(clone()を使用しない純なユーザレベルスレッディング)となるという点も納得できました。 また、恐らくGOMAXPROCを指定しない場合は、自動で現在で最適な論理CPU数にLWPを自動調整するような機能があり、それにより如何なる状況でも1:1スレッディング(NPTL等)に負けることはないのだと思いました。
guest

0

現代のLinuxには存在しない機構である、「System V や Solaris 時代の the traditional meaning な」LWP の説明を読んで、Linuxにそういうものがあると思い込んで質問をしているように見えます。「LWPがユーザレベル(=コードを書く立場)とカーネルレベルの橋渡しをする」ようなシステムを今使っている訳ではないですよね? と思ってしまいます。

LinuxではLWP=スレッドですよね。the traditional meaning なLWPとは意味が違って、「メモリを共有することで比較的軽い負荷で(=Light Weight)生成するプロセス」がLWPで、それを指してスレッドと呼んでるはずです。(「スレッドを実装するのにLWPを使っている」とも言えるかもしれません。スレッドがインタフェース/概念で、LWPが実装という対応になっているかと)

投稿2023/01/23 14:36

quickquip

総合スコア11029

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

akiyama3284pga

2023/01/24 04:19 編集

ありがとうございます。 色々と勘違いをしていることがわかりました。 今の理解で画像を再upしてみました。 確かに、LWPが橋渡しをしているというより、スレッド自身がユーザ空間とカーネル空間を切り替えながらあらゆる仕事をこなしていると思います。 ・カーネルモードになったLWP(スレッド)は、実行空間や、スケジューラの対象となるという点において、 性質上PPID2のカーネルスレッドと同じものになる(そういう意味でこの状態のスレッドはカーネルスレッドと呼べてしまうが、混乱するので使わないが吉)。 ・スレッドまたはプロセスが生成されるとき、clone()が実行される必要があるため、各スレッドは必ずカーネルモードから開始され、手続きを終えた後に、ユーザモードに戻る、つまり上の意味でのカーネルスレッドからユーザ空間のプロセス(thread)に戻ってユーザが書いたプログラムを実行する。(systemcallや割り込み等時も同様)
akiyama3284pga

2023/01/24 04:09

もしお暇がありましたら、またご指摘等頂けましたら助かります。 また、ウェブ等では色々な環境の教えが混在しており、上手く体系的に理解しにくいため、このあたりの現行のlinuxの知識を網羅している書籍等なにかあればご享受頂けたらと思います... 自分はこれからオライリーのシステムプログラミングという書籍を読んでみようと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問