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

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

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

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

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

6回答

6101閲覧

スレッドセーフな関数について

strike1217

総合スコア651

C

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

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2018/02/15 08:54

マルチスレッドについての質問になります。

まずは仕組み的なことの確認から・・・
スレッドは、固有のスタック領域を持ち、forkシステムコール同様にcloneシステムコールを発行する。
forkシステムコールと同様に・・・ということは、カーネル側はtask_structとしてスレッドを管理しているはずです。

するとマルチスレッドにおいて、レジスタ、スタック領域は他のスレッドと競合することはないことになります。

C/C++などの標準ライブラリにはスレッドセーフではない関数があります。
スレッドセーフではない C ライブラリ関数

自分が知っているものは「静的記憶期間に配置されるグローバル変数に書き込みや読み込みを行う」ような関数で、排他的制御がされていないもの」はスレッドセーフではない・・・ということです。(これしか知りません。)

これ以外にもこんな記述はスレッドセーフにはならないというものがあったら教えてください。
思い当たるのは例外処理ですかね??

上記のリンクにある「exit()」の説明は少し難しいですね。(割り込みについてですね。)
リエントラントではない関数についても原因は「排他的制御がされていないグローバル変数」のような気がするんですが・・・

しかし、
rand()、srand()のようなグローバル変数で実装されている関数は単純に排他的制御(ロック機能)をプログラマ側で用意すればマルチスレッドでも安全に利用可能ですよね??

これ以外にも
スレッドセーフではない関数をスレッドで安全に利用する方法があれば教えてください。

あとは、ライブラリに頼らずに自分で関数を作るとか・・・くらいしか思いつかないですが・・・

そもそもライブラリとして提供しているものがスレッドセーフでない・・・という事自体問題であるような気します。
ライブラリとして提供するならスレッドセーフな関数で実装してほしいですよね?

分かる方教えてください。

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

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

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

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

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

guest

回答6

0

「グローバル変数」だったらとか、ライブラリ関数のうちあるものだったらと言う考え方はやめた方が良いです。

まず、静的記憶期間に配置されているとか、グローバル変数とか、そんなものは関係ありません。ローカル変数であろうが、動的に確保した領域であろうが、どんな変数であろうが、スレッド間で共通で使用される領域を使用する物は全てスレッドセーフではない可能性があります。thread_localを使用した領域のようにスレッド間で独立して確保された領域以外は全て危険です。

次に、ある関数は…という考えも辞めた方が良いです。単純な整数のインクリメント++ですらスレッドセーフではありません

https://wandbox.org/permlink/Jy4VupXEuZt5xF79

上記では1000000回インクリメントを4スレッドにわけておこなっていますが、多くの場合で4000000にはなりません(環境によってはなる場合もあります)。これを4000000になるように保証するには、std::atomic等を使う必要があります。

https://wandbox.org/permlink/BwTTPifBDcZWhgh0

このように、非常に単純な操作ですら、スレッドセーフであることが保証されていない場合があります。上記のstd::atomicのようにドキュメントや仕様でスレッドセーフであることが明記されているもの以外は全てスレッドセーフではないという前提でプログラミングを行うべきです。私の知る限り、標準のC++においては、std::threadやstd::mutex等周りのマルチスレッド操作に関する関数とアトミック操作を保証するstd::atomic関係以外に、どのような環境でもスレッドセーフであることが保証された物は見たことがありません。


話は別として、スレッドセーフではないライブラリをマルチスレッド環境でも安全に使いたい場合、通常は排他制御でライブラリ関数の多重呼び出しを防止します。しかし、排他制御自体が重いため、呼び出しの前後で毎回処理を無条件で入れていくのは非効率だという考えがあります。では、どうするかというと、考え方を転回させて、基本的には同時に一つのスレッドしか動かないようにし、スレッドセーフなライブラリの呼び出しのみ並列で動作しても良いとする、と言うのがあります。スレッドセーフではないコードがほとんどの場合は、こちらの方が効率が高いからです。

そんな実装している物があるのかというと、あります。PythonとRubyです。この二つの言語はマルチスレッドをサポートしていますが、グローバルインタープリンタロック(GIL)という機能を搭載しています。どんなにスレッドを増やしても、その時動いているのはたった一つのスレッドになるようにするというものです。この環境では、外部のC/C++で作られたライブラリの呼び出しは、常にたった一つのスレッドから行われるため、二重に呼び出して壊れることはありません。逆に、二重で呼び出しても良い物は、そのときだけ別スレッドを動かしても良いよとして、効率化を図ります。

これが良いのか悪いのかはわかりません。Rubyのコミュニティでは、GILは外すべきだ、という意見が時々出るそうです。ですが、GILを前提にした方が、実装もしやすく、シングルスレッドの処理で余計な排他処理を入れなくても良いので速いという利点があります。マルチコアを有意義に使いたい場合は、制限がある分安全になるマルチプロセスを使えばいいと言うことのようです。嬉しいことに、PythonもRubyも簡単にマルチプロセスで動かすためのライブラリが存在するので、そこまで問題ではないのかもしれません。

投稿2018/02/15 16:29

raccy

総合スコア21737

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

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

strike1217

2018/02/15 16:47

「基本的には同時に一つのスレッドしか動かないようにし、スレッドセーフなライブラリの呼び出しのみ並列で動作しても良いとする」 ふむふむ・・・ これはつまり、同時に1つのスレッドしか動かさないようにする → 同時に1つしか動いていない時にはスレッドセーフではない関数を利用しても問題ない! ということですよね。
strike1217

2018/02/15 16:54

「基本的には同時に一つのスレッドしか動かないようにする」 この部分については疑問があるので再度質問します。
maisumakun

2018/02/16 03:02

ちょうど別件でRubyのGVLについて回答したのですが、どちらも言語仕様としてではなく、あくまでC言語による実装(CRuby、CPython)の問題です。 JVM上に実装されたJRubyやJythonは、JVM自体の並列実行を活かして、それぞれの言語で書かれたスレッドが並列に動作します(逆を言えば、きちんと排他処理しないとトラブルになります)。
guest

0

ベストアンサー

「静的記憶期間に配置されるグローバル変数に書き込みや読み込みを行う」ような関数で、排他的制御がされていないもの」はスレッドセーフではない
これ以外にもこんな記述はスレッドセーフにはならないというものがあったら教えてください。

上記理解で概ね正しいと思います。スレッドセーフでない関数の例としては、外部I/Oを伴うものが上げられます。

  • 画面を制御する関数(標準入出力)
  • ネットワーク通信を制御する関数
  • 外部デバイスを制御する関数
  • など

また、プロセスを制御する関数とマルチスレッド処理の組み合わせでは特別な注意が必要なケースがあります。UNIX系OSでは fork関数 とマルチスレッド処理の組み合わせは避けたほうが無難です。

rand()、srand()のようなグローバル変数で実装されている関数は単純に排他的制御(ロック機能)をプログラマ側で用意すればマルチスレッドでも安全に利用可能ですよね??

適切に排他制御を行えば、マルチスレッド環境でも異なるスレッドから“安全”に呼び出し可能です。ただし、そのときの振る舞いが望ましい結果になるか否かは十分注意が必要です。現実的には、グローバル変数や静的変数に依存する関数を、マルチスレッド環境で利用することは出来ません。
(ここでいう“安全”とは、C/C++言語仕様的には問題無いという狭い意味にすぎません。)

乱数を生成する rand() の場合、複数スレッドからどのような順序で関数が呼び出されても乱数列に代わりありません。リエントラント(reentrant)でない関数、例えば strtok() などの「外から見えない内部状態を保持する関数」では、複数スレッドから任意の順序で呼び出されると各スレッド上で得られる振る舞いが予測不可能になってしまい、事実上使い物になりません。


そもそもライブラリとして提供しているものがスレッドセーフでない・・・という事自体問題であるような気します。
ライブラリとして提供するならスレッドセーフな関数で実装してほしいですよね?

一般論として、ある処理をスレッドセーフに実装するには何らかのオーバーヘッドを伴います。ライブラリ提供の関数をスレッドセーフにするか否かは、安全性と性能のトレードオフという ライブラリ仕様設計上の選択 です。

例えば、ほとんどのGUIフレームワークでは、UI部品を操作する関数はスレッドセーフな仕様になっておらず、特定のスレッド(≒UIスレッド)以外から関数呼出しを行うとエラーが発生します。これらの関数をスレッドセーフに実装することも不可能ではありませんが、多くのGUIフレームワークでは動作性能や内部実装の複雑化を避けるため、意図的に「スレッドセーフではない外部仕様」を採用します。

投稿2018/02/15 10:07

編集2018/02/15 10:18
yohhoy

総合スコア6191

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

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

maisumakun

2018/02/15 10:08

噂をすれば…じゃないですけど、参考にリンクを使わせてもらいました。
strike1217

2018/02/15 11:45 編集

画面を制御する関数(標準入出力) ネットワーク通信を制御する関数 外部デバイスを制御する関数 こちらを見ますと、共有資源に対する関数ですよね。 そういう意味では、グローバル変数と同じようなものと考えることができますが・・・ つまり、スレッドセーフでない関数とは、共有資源に対して排他的でない関数 これだけ・・・と考えれば良いのでしょうか? 共有資源以外のケースというものもあるのでしょうか?
strike1217

2018/02/15 11:45

> ある処理をスレッドセーフに実装するには何らかのオーバーヘッドを伴います。 ロックのことですね。 > ライブラリ提供の関数をスレッドセーフにするか否かは、安全性と性能のトレードオフという ライブラリ仕様設計上の選択 です。 なるほど! 技術的にグローバル変数に頼らなくてはならない関数だとどうしてもそうなってしまいますね!
strike1217

2018/02/15 12:50

標準入出力系の関数がスレッドセーフでないとすると確かにprintfもスレッドセーフではないことになりますよね? printf関数は書き込みのみであり、グローバル変数が使用されていないなら、排他的制御なしマルチスレッドでの利用も問題ないように思えるのですが・・・
strike1217

2018/02/15 14:34

「そのときの振る舞いが望ましい結果になるか否かは十分注意が必要です。」 これはなぜですか?? 排他的制御を行うだけで「プログラマの意図した通りの結果」にならない可能性がある・・・ということだと思うのですが・・・その理由が分かりません。
yohhoy

2018/02/15 14:43 編集

>> ある処理をスレッドセーフに実装するには何らかのオーバーヘッドを伴います。 > ロックのことですね。 ロック(排他制御)は実装選択肢の一つですが、スレッドセーフの実現方法の全てではありません。スレッドセーフな内部実装として、文字通りロックを利用しない「ロックフリー(lock-free)アルゴリズム」という選択肢もありえます。 > 標準入出力系の関数がスレッドセーフでないとすると確かにprintfもスレッドセーフではないことになりますよね? 「スレッドセーフ」という用語は広く使われますが、実際のところ共通の定義は存在しません。対象となるプログラミング言語(やそのユーザの文化圏)ごとに異なる概念だったりします。 > printf関数は書き込みのみであり、グローバル変数が使用されていないなら、排他的制御なしマルチスレッドでの利用も問題ないように思えるのですが・・・ 問題の本質は「リソース(資源)の共有」です。グローバル変数はスレッド間でメモリを共有しますが、標準入出力はスレッド間でコンソールを共有しています。 複数スレッドから同時に文字列を出力する場合(例えば"Hello"と"Goodbye")、スレッドの進行状況によってコンソールという資源の取り合いが発生すると、最終的には"GHoeoldlboye"のように文字列が混じることがありえます。(実際にはもっと長い文字列同士でないと現象は表面化しないでしょう) このとき2段階のスレッドセーフ・レベルが考えられます。スレッドセーフの考え方は○/×だけで表現できる2原論ではないのです。 1) 各スレッドが出力する文字が「欠落や重複したりしないこと」 2) 各スレッドが出力する「文字列が混じらないこと」
strike1217

2018/02/15 14:46

> 「スレッドセーフ」という用語は広く使われますが、実際のところ共通の定義は存在しません。 げげ!! 難しいですね。定義が曖昧だと頭が痛い。 ああ!printfの説明の箇所はとても分かりやすいですね。 「セーフ」という言葉自体が既に難しいですね。
strike1217

2018/02/15 15:18 編集

printfのようなスレッドセーフと書いてある関数であっても油断できないないわけですね。 この場合はロック機能で回避できそうですが・・・ 一般的にスレッドセーフでないと言われている関数を排他的に制御しても「プログラマの意図しない動作」になる場合ってあるんでしょうか?? その場合、そのような関数の利用はもはや諦めるしかないですよね。
strike1217

2018/02/15 15:02

いかなる関数も排他的に制御すれば、プログラマの意図した通りに動くと考えるのはマズイですかね??
yohhoy

2018/02/16 02:56 編集

> 一般的にスレッドセーフでないと言われている関数を排他的に制御しても「プログラマの意図しない動作」になる場合ってあるんでしょうか?? > その場合、そのような関数の利用はもはや諦めるしかないですよね。 マルチスレッド環境から安全に使えない関数は、諦めるほかありません。C/C++言語であれば、「リエントラントでない関数」はマルチスレッドプログラムでは使い物になりません。利用は諦めてください。大抵は、代替関数が提供されています。 > いかなる関数も排他的に制御すれば、プログラマの意図した通りに動くと考えるのはマズイですかね?? マズイです。全パターンに適用できる魔法の解決手段はありません。 つ「銀の弾などない」
strike1217

2018/02/16 05:24

わかりました。 ありがとうございます。
guest

0

リンク先の関数は、あくまでも「ARM ソフトウェア開発ツールが提供するライブラリーの中でスレッドセーフではないもの」であり、同じ関数でもGCCやVC++ではスレッドセーフのものがあったりします。要するに、スレッドセーフかどうかは処理系(ライブラリーの実装)の問題であって、例えばVC++では/MTあるいは/MDオプションによってリンクされるマルチスレッド版ランタイムライブラリーでは、ほとんどの関数(すべてかどうかは未確認)がスレッドセーフです。

自分が知っているものは「静的記憶期間に配置されるグローバル変数に書き込みや読み込みを行う」ような関数で、排他的制御がされていないもの」はスレッドセーフではない・・・ということです。(これしか知りません。)

例えば、rand()、srand()は、一般的な実装ではグローバル(というか静的な領域)に変数を確保しているのでスレッドセーフではないことが多いですが、私の知る限りでは、VC++のマルチスレッド版ランタイムライブラリーでは、TLS(Thread Local Storage)という仕組みを利用することで排他制御なしにスレッドセーフを実現しています。他の静的領域に変数を持たせている関数も同様です。

rand()、srand()のようなグローバル変数で実装されている関数は単純に排他的制御(ロック機能)をプログラマ側で用意すればマルチスレッドでも安全に利用可能ですよね??

安全とは何かを定義する必要があります。少なくとも、期待通りに動作しないかもしれない、という危険性があります。その辺はyohhoyさんの説明の通りですね。

どうしても静的領域に変数を持たせないといけないような関数を実装する際、TLSの使い方を知っておくと、排他制御のような余分なコストをかけずにスレッドセーフにできます。もちろんすべてのケースでできるとは限りませんが。

投稿2018/02/15 13:00

catsforepaw

総合スコア5944

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

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

strike1217

2018/02/15 13:04

「スレッドセーフかどうかは処理系(ライブラリーの実装)の問題」 左様でございますか!! TLSについては以前質問させてもらいました! 「排他制御のような余分なコストをかけずにスレッドセーフにできます」 ほお!なるほど! 改めて理解が深まりした。
guest

0

こんにちは。

これ以外にもこんな記述はスレッドセーフにはならないというものがあったら教えてください。

思い当たるのは例外処理ですかね??

基本的には「スレッドセーフと書かれていないものは全てスレッドセーフではない」と考えるのが望ましいです。
同じメモリへの複数の同時アクセスで、少なくとも1つ書き込みがあるものが危険です。何も考えずにプログラムを書くと、この状況は極簡単に発生しますから、これを慎重に回避する必要があるからです。

静的領域(グローバル変数やstaticローカル変数)は、きっちり意識しないと複数のスレッドから簡単にアクセスできるのでハマります。(staticローカル変数はそれを定義している関数を複数のスレッドが同時に呼び出すと同時アクセスが発生する可能性があります。)

ヒープ領域を複数のスレッドで同時アクセスする場合、多少は起きにくいですが、複数のスレッドでポインタ経由で同じヒープ上のオブジェクトを共有することも油断すると発生しますので、やはり危険です。(例えば、C++ではないですが、C#のGUIオブジェクトが該当します。)

スタック領域のオブジェクトへのポインタを複数のスレッドで共有することはレアと思いますが、原理的には有りえます。

そこで、私自身は複数のスレッドで同じメモリへアクセスするものは全て危険と認識し、危険な状況を確実に回避するよう慎重に慎重に設計します。(回避しそこなうと再現性の非常に低い、むちゃくちゃ頭の痛いバグになります。デバッグは地獄です。)

上記のリンクにある「exit()」の説明は少し難しいですね。

機械翻訳されているような文章ですね。判りにくいというか日本語になっていないと思います。(割り込みではなくシグナル、もしくは、例外かも?)

rand()、srand()のようなグローバル変数で実装されている関数は単純に排他的制御(ロック機能)をプログラマ側で用意すればマルチスレッドでも安全に利用可能ですよね??

基本的にはその通りです。しかし、ロック機構はデッドロックのリスクがありますので、必ずしも安全になるわけではありません。ロックする時はデッドロックしないことに要注意です。経験的にはスレッドを終了させる際に発生しやすいです。(呼び出し側がスレッド終了を待ち、スレッドは呼び出し側スレッドの応答を待っているなど。)

とはいえ、同じメモリへの書き込みと読み出しがあるなら、通常は比較的安易にMutexでロックしてます。
そして、複数のロックを待つ処理がないことをチェックしています。

投稿2018/02/15 12:47

編集2018/02/15 12:54
Chironian

総合スコア23272

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

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

strike1217

2018/02/15 12:54

「staticローカル変数はそれを定義している関数を複数のスレッドが同時に呼び出すと同時アクセスが発生する可能性があります」 staticな変数は確かに静的記憶期間に配置されますが、ロカールな場合であっても競合が発生するんですか!! 初めて知りました。
Chironian

2018/02/15 12:58

1つの関数は当然複数のスレッドから呼べます(正に議論している状況かと)。その関数内のstaticローカル変数は異なるスレッドから呼び出された場合でも同じメモリ領域を使用しますから、同時アクセスが発生する可能性がありますよ。 なお、thread_local指定すればスレッド毎に確保されます。
strike1217

2018/02/15 13:00

ほぉぉ! そうなんですね!!
strike1217

2018/02/15 13:00

「スレッドセーフでない関数 = 共有資源に対して排他的ではない関数」 これ以外の場合、つまり共有資源へのアクセス以外でスレッドセーフにならない場合があるのか疑問なんです。
Chironian

2018/02/15 13:15 編集

それって用語の定義の問題と思います。私自身は、そもそも共有資源へのアクセスそのものまでは「スレッドセーフでない」には含めていません。 一般に、近代的なOSが管理する資源へマルチスレッド・アクセスしてもシステムもアプリも落ちませんので。出力や入力の順序が制御できず困ったことになることはあります。これを回避するのに「ロック機構」を使う場合もありますが、それ以外の方法(例えばhttpのクッキーにもその役割があります)を使う場合もあるでしょう。これらの議論は範囲が広すぎて発散します。 私自身は、OSではなくライブラリやユーザプログラムが管理するメモリへのアクセス方法についてスレッドセーフやそうでないという表現をすることが多いです。
Chironian

2018/02/15 13:29 編集

ああ、exit()が何故複数のスレッドから呼び出しては行けないか?という話ですか? 単なる憶測ですが、exit()がメイン・スレッド以外の全てのスレッド終了を待っているのかもしれません。 そして、サブ・スレッドから呼び出すと、自分自身の終了待ちをするから、デッドロックが発生するとか? そして、自分自身の終了待ちならデッドロックをOSが検出できて全てのスレッドにシグナルを送るとかかも。
strike1217

2018/02/15 13:42

ああ。すいません。 そういうことではなくてですね。 えーーと簡単に述べますとですね。 スレッドセーフではない関数と言われているものは、調べると「共有資源に対する制御が不適切である」と言ったことしか出てこないんですよね。 なので、「共有資源に対する」ではなく、それ以外のケースで「スレッドセーフではない」場合があるのかな?? という疑問です。 exit()もそうですね。それ以外にはどのような場合にスレッドセーフにならないのかな??という疑問ですね。
Chironian

2018/02/15 14:44

> 「共有資源に対する」ではなく、それ以外のケースで「スレッドセーフではない」場合があるのかな?? 「スレッドセーフでない」と仕様書にかかれている場合は該当しますね。そして、それは共有資源アクセスによるものが多いと思います。 それ以外のものについては仕様書に理由が書かれていない場合は分からないです。exit()関数はこれに該当します。もしかすると、main関数を起動したスレッドでないと終了処理がうまくいかない構造なのかも知れません。この辺は中身を知る人でないと解らないと思います。
strike1217

2018/02/15 14:46

なるほど! わかりました。
guest

0

これ以外にもこんな記述はスレッドセーフにはならないというもの

いちばんかんたんな例で、printfがあります。標準出力は1つしかないので、それに対して複数スレッドから同時に書き込みを行えば、結果は保証されません。

そもそもライブラリとして提供しているものがスレッドセーフでない・・・という事自体問題であるような気します。

原理的に、標準入出力に依存するものはどうしようもありません。

rand()、srand()のようなグローバル変数で実装されている関数は単純に排他的制御(ロック機能)をプログラマ側で用意すればマルチスレッドでも安全に利用可能ですよね??

そもそもrandは品質が悪すぎるので、はなから別なものを使うべきでしょう。

投稿2018/02/15 09:45

maisumakun

総合スコア145930

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

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

strike1217

2018/02/15 09:53 編集

printf関数ってスレッドセーフでしたよね?? 確かに言われてみると、「それに対して複数スレッドから同時に書き込みを行えば、結果は保証されません。 」・・・その通りですね。 つまり、マルチスレッドにおけるprintf関数の出力する結果はあてにならない・・・ということですか? (例えば、出力される順序など)
strike1217

2018/02/15 09:58

fmfm 読んでみますわ
guest

0

再入可能コードおよびスレッド・セーフ・コードの作成

ここによりますと、
スレッドセーフな関数 = ロックを使用して共用リソースを同時アクセスから保護する

となっています。
つまり、「それ以外の場合はない」というのが結論のようです。

EXIT

exit() 関数は保護されていないグローバル変数を使用しているため、スレッドセーフではない。

とのことです。

つまり、スレッドセーフという言葉の定義が共有資源に対して排他的制御がされているということなんですね!!

記述の仕方ではなく、共有資源に対する制御が言葉の定義になっているんですね!
難しいいいい!
勘違いをしていました。

「printf関数について」
printf() — 定様式の文字の出力
printf()はスレッドセーフのようですね。

投稿2018/02/15 14:11

編集2018/02/15 14:12
strike1217

総合スコア651

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

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

strike1217

2018/02/15 14:15

ということは・・・「スレッドセーフではない全てのライブラリ関数」はプログラマが排他的制御を行えば、利用しても大丈夫ということになりますよね。
strike1217

2018/02/15 14:17 編集

逆に言えば、プログラマが排他的制御を行えば、スレッドセーフではない関数など存在しません。 ・・・ということになりそうですが・・・本当にそうなのかなぁ?
catsforepaw

2018/02/15 15:11

> 再入可能コードおよびスレッド・セーフ・コードの作成 > ここによりますと、 > スレッドセーフな関数 = ロックを使用して共用リソースを同時アクセスから保護する > となっています。 > つまり、「それ以外の場合はない」というのが結論のようです。 いや、結論になっていませんから。スレッドセーフの手段に関しては「実装依存」ですから。 リンク先を見ましたが、それはIBMのILE C/C++という開発環境に関する記述なので、ILE C/C++固有の情報です。 > つまり、スレッドセーフという言葉の定義が共有資源に対して排他的制御がされているということなんですね!! 違います。 スレッドセーフという言葉には「複数スレッドから同時に実行されても安全」という意味しかありません。どのようにその安全性を保証するかは、前述のように実装依存となります。排他制御というのはその手段の一つであって、それがすべてではありません。TLSを用いた手法はすでに私の回答で説明していますし、作業用領域を呼び出し側で用意するなども一般的なスレッドセーフの手法です。それらは「資源を共有しない」ことでスレッドセーフを実現しています。 他にも手法はいろいろあると思います。 > printf()はスレッドセーフのようですね。 前述の通り、その情報はILE C/C++固有の情報なので、そのまま他の処理系に当てはまるものではありません。
strike1217

2018/02/15 15:17 編集

はい、yohhoyさんのコメントを見ました。 ここの欄の考察は不適切でした。 すいません。
strike1217

2018/02/15 15:14

「安全とは何かを定義する必要があります」 catsforepawさんの仰る通りです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問