web-dev-qa-db-ja.com

「スレッドセーフ」とは実際には...実用的には

私の初心者の質問に耐えてください。

ASP.NETとC#でghostscriptを使用してPDFをPNGに変換しようとしました。しかし、ghostscriptはスレッドセーフではないことも読みました。したがって、私の質問は次のとおりです。

  1. 「ghostscriptはスレッドセーフではない」とは、実際にはどういう意味ですか?多くの同時ユーザーが同時にアクセスするライブASP.NET(aspx)Webアプリケーションで使用すると、どのような影響がありますか?

  2. また、別のサイトから、ghostscriptver。の主な機能を読んだ。 8.63はマルチスレッドレンダリングです。これは、スレッドセーフの問題が解決されたことを意味しますか? ghostscriptスレッドは安全ですか?

  3. また、スレッドセーフであると思われるPDFTronのPDF2Imageも評価しています。しかし、CPUごとのライセンスは安くはありません。 「スレッドセーフ」と「安全ではない」のどちらに追加料金を支払う価値はありますか?

43
N_R

たとえば、コレクションが脅威ではない場合、次のようになります。

var myDic = new Dictionary<string, string>();

マルチスレッド環境では、これは次をスローします。

string s = null;
if (!myDic.TryGetValue("keyName", out s)) {
    s = new string('#', 10);
    myDic.Add("keyName", s);
}

1つのスレッドがKeyValuePairを辞書myDicに追加しようとしているときに、別のスレッドがTryGetValue()を実行する可能性があります。コレクションの読み取りと書き込みを同時に行うことはできないため、例外が発生します。

ただし、一方で、これを試してみると:

// Other threads will wait here until the variable myDic gets unlocked from the preceding thread that has locked it.
lock (myDic) {
    string s = null;
    if (!myDic.TryGetValue("keyName", out s)) {
        s = new string('#', 10);
        myDic.Add("keyName", s);
    }
} // The first thread that locked the myDic variable will now release the lock so that other threads will be able to work with the variable.

次に、突然、同じ「keyName」キー値を取得しようとする2番目のスレッドは、最初のスレッドがすでに追加したので、それを辞書に追加する必要がなくなります。

つまり、スレッドセーフとは、オブジェクトが複数のスレッドによる同時使用をサポートすること、またはスレッドセーフを心配することなくスレッドを適切にロックすることを意味します。

2。 GhostScriptがスレッドセーフになったとは思いません。主に複数のスレッドを使用してタスクを実行しているため、パフォーマンスが向上します。それだけです。

予算と要件によっては、価値があるかもしれません。ただし、ラッパーを中心に構築する場合は、都合のよい場所でのみlock()を実行できます。または、マルチスレッドを自分で使用しない場合は、スレッドセーフにお金を払う価値はありません。これは、アプリケーションがマルチスレッドを使用している場合、ライブラリがスレッドセーフでないという結果に悩まされることはないということだけを意味します。本当にマルチリードしない限り、スレッドセーフなライブラリにお金を払う価値はありません。

22

誰もが同意する正確な技術的定義を思い付くのは困難です。

非公式には、「スレッドセーフ」とは、単に「複数のスレッドから呼び出されたときに適切に動作する」ことを意味します。複数のスレッドから呼び出されたときに、オブジェクトがクラッシュしたり、クレイジーな結果を生成したりすることはありません。

特定のオブジェクトを含むマルチスレッドプログラミングを行う場合に実際に回答する必要がある質問は、「オブジェクトが期待するスレッドモデルは何ですか?」です。

さまざまなスレッドモデルがたくさんあります。たとえば、「フリースレッド」モデルは、「任意のスレッドから好きなことを実行します。オブジェクトがそれを処理します」です。これは、対処するのが最も簡単なモデルであり、オブジェクトプロバイダーが提供するのが最も難しいモデルです。

スペクトルのもう一方の端には、「シングルスレッド」モデルがあります。すべてのオブジェクトのすべてのインスタンスは、単一のスレッド、期間からアクセスする必要があります。

そして、真ん中にたくさんのものがあります。 「アパートメントスレッド」モデルは、「2つの異なるスレッドで2つのインスタンスを作成できますが、インスタンスの作成に使用するスレッドは、そのインスタンスのメソッドを呼び出すために常に使用する必要があるスレッドです」です。

「レンタルスレッド」モデルは、「2つの異なるスレッドで1つのインスタンスを呼び出すことができますが、2つのスレッドが同時に呼び出さないようにする責任があります」です。

等々。オブジェクトに対してスレッドコードを記述しようとする前に、オブジェクトが期待するスレッドモデルを確認してください。

38
Eric Lippert

私はGhostscript開発者であり、スレッドセーフに関する一般的な理論を繰り返すことはありません。
単一のプロセス内からgsapi_new_instanceを使用して複数の「インスタンス」を作成できるように、GSをスレッドセーフにするために取り組んできましたが、これはまだ満足のいくものではありません(QAテストを含むこの)。
ただし、グラフィックライブラリはスレッドセーフであり、マルチスレッドレンダリングはこれに依存して、複数のスレッドを生成し、ディスプレイリストからバンドを並列にレンダリングできるようにします。マルチスレッドレンダリングは、多くのQAテストを受けており、マルチコアCPUのパフォーマンスを向上させるために多くの商用ライセンシーによって使用されています。

最終的にGSの複数のインスタンスをサポートするときに発表することは間違いありません。複数のインスタンスを必要とするアプリケーションから現在のGSを使用したいほとんどの人は、インスタンスごとに個別のプロセスを生成するため、GSはスレッドセーフである必要はありません。 GSは、引数リストオプションによって決定されたジョブを実行するか、I/Oをプロセスとの間でパイプ処理して、データを提供し、出力を収集することができます。

11
Ray Johnston

1)複数のスレッド間で同じGhostscriptオブジェクトまたはフィールドを共有すると、クラッシュすることを意味します。例えば:

private GhostScript someGSObject = new GhostScript();
...
// Uh oh, 2 threads using shared memory. This can crash!
thread1.Use(someGSObject);
thread2.Use(someGSObject);

2)私はそうは思いません-マルチスレッドレンダリングは、GSが内部的に複数のスレッドを使用してレンダリングしていることを示唆しています。 GSが複数のスレッドからの使用に対して安全ではないという問題には対処していません。

3)そこに質問はありますか?

GhostScriptスレッドを安全にするには、一度に1つのスレッドだけがそれにアクセスしていることを確認してください。これは、ロックを介して行うことができます。

lock(someObject)
{
   thread1.Use(someGSObject);
}
lock(someObject)
{
   thread2.Use(someGSObject);
}
10

シェルオブジェクトからghostscriptを使用している場合(つまり、ファイルを処理するためにコマンドラインを実行している場合)、実行中のすべてのインスタンスがサーバー上の異なるプロセスで実行されるため、スレッドの問題に巻き込まれることはありません。注意が必要なのは、PDFを処理するためにC#から使用しているdllがある場合、2つのスレッドが同じコードを同時に実行しないように、そのコードを同期する必要がある場合です。

3
Bryan Rehbein
  1. スレッドセーフとは、基本的に、複数のスレッドからアクセスされた場合でも、コードの一部が正しく機能することを意味します。スレッド化されたアプリケーションで非スレッドセーフコードを使用すると、複数の問題が発生する可能性があります。最も一般的な問題はデッドロックです。ただし、スレッドの問題はデバッグが難しいことで有名なため、さらに多くの問題になる可能性のある、はるかに悪質な問題(競合状態)があります。

  2. いいえ。マルチスレッドレンダリングとは、GSがスレッドを使用してレンダリングするため、より高速にレンダリングできることを意味します(理論的には、とにかく、実際には常に正しいとは限りません)。

  3. それは本当にあなたがあなたのレンダラーを何のために使いたいかによります。複数のスレッドを使用してアプリケーションにアクセスする場合は、はい、スレッドセーフであることを心配する必要があります。そうでなければ、それは大したことではありません。

2
JasCav

一般に、これはあいまいな用語です。

スレッドセーフは、共有データの正しい同期が行われる概念レベルである可能性があります。これは通常、ライブラリライターが意味するものです。

場合によっては、並行性が言語レベルで定義されていることを意味します。つまり、言語のメモリモデルは同時実行をサポートします。これはトリッキーです!なぜなら、ライブラリライターとして並行ライブラリを作成することはできないからです。言語には、使用する必要のある多くの重要なプリミティブに対する保証がないからです。これは、ライブラリユーザーよりもコンパイラライターに関係します。その意味で、C#はスレッドセーフです。

私はあなたの質問に直接答えなかったことを知っていますが、それが役立つことを願っています。

1
AraK