1

2 つの連続する式の間、関数の呼び出しとその本体の最初の式の実行の間、またはコンストラクターの呼び出しとその初期化子の実行の間で何が起こるかについて、私はめったに考えたことがありません。それから私は並行性について読み始めました...

1.)本体が同じオブジェクトの初期化でstd::thread始まる、同じ callable (関数、ファンクター、ラムダなど) を持つ のコンストラクターへの 2 つの連続した呼び出しで、最初のコンストラクター呼び出しに対応するスレッドがロックを実行することを標準で保証しますか? -最初に保護されたコード?std::lock_guardstd::mutexthread

2.) 標準が保証しない場合、2 番目のthreadコンストラクター呼び出しに対応するスレッドが最初に保護されたコードを実行する可能性は理論的または実際的にありますか? thread(たとえば、最初のコンストラクター呼び出しのイニシャライザーまたは本体の実行中の重いシステム負荷)

これは、グローバルstd::mutexオブジェクトmと にunsigned num初期化されたグローバル1です。foofunctionの本体の左中括弧{と. の間には空白しかありませんstd::lock_guard。には、 と のmain2 つがstd::threadありt1ますt2t1最初にスレッド コンストラクターを呼び出します。t2スレッド コンストラクタを 2 番目に呼び出します。各スレッドは へのポインタで構築されますfoo。引数でt1呼び出します。引数で呼び出します。どちらのスレッドが最初にロックするかに応じて、両方のスレッドがロック保護されたコードを実行した後、 の値は aまたは aになります。等しくなりますfoounsigned1t2foounsigned2mutexnum43num4ロックにt1打ち込む場合。t2それ以外の場合は、numに等しくなり3ます。ループして各ループの最後にリセットすることで、numこれを 100,000 回試行しました。1(私の知る限り、結果はどのスレッドがjoin()最初に編集されるかに依存しませんし、依存すべきではありません。)

#include <thread>
#include <mutex>
#include <iostream>

std::mutex m;
unsigned short num = 1;

void foo(unsigned short par) {
    std::lock_guard<std::mutex> guard(m);
    if (1 == num)
        num += par;
    else
        num *= par;
}

int main() {
    unsigned count = 0;
    for (unsigned i = 0; i < 100000; ++i) {
        std::thread t1(foo, 1);
        std::thread t2(foo, 2);
        t1.join();
        t2.join();
        if (4 == num) {
            ++count;
        }
        num = 1;
    }
    std::cout << count << std::endl;
}

最終的には にcount等しい100000ので、t1毎回レースに勝つことがわかります。しかし、これらの試験は何も証明しません。

3.) 「threadコンストラクターを最初に呼び出す」という標準の命令は、常に「コンストラクターに渡された呼び出し可能オブジェクトを最初に呼び出す」ことを意味しthreadますか?

4.) 「コンストラクターに渡された callable を最初に呼び出す」という標準の命令は、常に「最初にロックする」threadことを意味しますか? mutexcallable の本体内に、初期化の行の前に callable に渡されたパラメーターに依存するコードが存在しない場合はstd::lock_guard? static(また、特定の呼び出しを意図的に遅らせるために使用できる、呼び出された回数のカウンターなど、呼び出し可能オブジェクトのローカル変数も除外します。)

4

1 に答える 1

3
  1. いいえ、標準では、最初のスレッドが最初にロックを取得することは保証されていません。基本的に、スレッド間でインポーズと順序付けが必要な場合は、これらのスレッド間で同期する必要があります。最初のスレッドが最初にミューテックス ロック関数を呼び出したとしても、2 番目のスレッドが最初にロックを取得する可能性があります。
  2. 絶対。たとえば、スレッドが生成された時点でアプリケーションで使用できるコアが 1 つだけである場合、生成スレッドが 2 番目のスレッドが生成された後に何かを待機することを決定した場合、スケジュールは確認された最新のスレッドを処理することを決定する可能性があります。 2番目のスレッド。使用可能なコアが多数ある場合でも、2 番目のスレッドの方が高速である理由はたくさんあります。
  3. いいえ、どうしてでしょう!最初のステップは、スレッドを生成して続行することです。最初の関数オブジェクトが呼び出されるまでに、2 番目のスレッドが実行され、その関数オブジェクトを呼び出すことができます。
  4. いいえ。同時実行の目的を無効にするため、明示的に自分で強制しない限り、スレッド間の順序保証はありません。
于 2014-01-11T01:23:53.483 に答える