5

同じをロックしようとしている 2 つのスレッドがありboost::mutexます。これらのスレッドの 1 つは継続的に一部のデータを処理しており、もう 1 つは定期的に現在の状態を表示しています。私の意図によると、処理スレッドは非常に頻繁にロックを解放して再取得するため、表示スレッドは必要なときにいつでもロックをタップして取得できます。したがって、明らかに、次にプロセス スレッドによってロックが解放されたときに、ディスプレイ スレッドがロックを取得するようにしたいと考えています。ただし、それは行わず、代わりにロックを待機し、プロセス スレッドからの多くのロック解放サイクルの後にのみロックを取得します。

私の問題を示す最小限の例を調べてください:

#include <boost/thread.hpp>
#include <iostream>

using namespace std;
using namespace boost;

mutex mut;

void process() {
        double start = time(0);
        while(1) {
                unique_lock<mutex> lock(mut);
                this_thread::sleep(posix_time::milliseconds(10));
                std::cout<<".";
                if(time(0)>start+10) break;
        }
}

int main() {

        thread t(process);

        while(!t.timed_join(posix_time::seconds(1))) {
                posix_time::ptime mst1 = posix_time::microsec_clock::local_time();
                cout<<endl<<"attempting to lock"<<endl;
                cout.flush();

                unique_lock<mutex> lock(mut);

                posix_time::ptime mst2 = posix_time::microsec_clock::local_time();
                posix_time::time_duration msdiff = mst2 - mst1;
                cout << std::endl<<"acquired lock in: "<<msdiff.total_milliseconds() << endl;
                cout.flush();
        }

}

以下でコンパイル:g++ mutextest.cpp -lboost_thread -pthread

実行可能ファイルを実行すると、出力例は次のようになります。

...................................................................................................
attempting to lock
....................................................................................................................................................................................................................................................................................................................................................................................................................................
acquired lock in: 4243
...................................................................................................
attempting to lock
........................................................................................................
acquired lock in: 1049
...................................................................................................
attempting to lock
........................................................................................................................
acquired lock in: 1211
....................................

ご覧のとおり、最悪の場合、ディスプレイ スレッドは、ロックを取得するまでに 424 回のロックと解放のサイクルを待機します。

私は明らかにミューテックスを間違った方法で使用していますが、これを解決する通常の方法は何ですか?

4

5 に答える 5

1

boost::condition_variable、特にメソッドwait()およびnotify_one()またはを確認することをお勧めしますnotify_all()。このメソッドwait()は、ロックが解除されるまで現在のスレッドをブロックします。メソッドnotify_one()およびメソッドnotify_all()は、ロックが実行を継続するのを待っている 1 つまたはすべてのスレッドに通知します。

于 2013-04-05T15:42:49.010 に答える
1

更新スレッドが他に何もすることがない場合、mutex が使用可能になるまで待つことができます。

boost::condition_variable を見てください。ここでそれについて読むことができます http://www.boost.org/doc/libs/1_53_0/doc/html/thread/synchronization.html と ここ ブースト条件変数の使用

更新スレッドをスリープ状態にすることが問題になる場合 (多くの GUI システムで発生し、使用しているシステムを指定しない場合)、処理スレッドから更新スレッドにメッセージを投稿することを検討してください。(詳細はプラットフォームによって異なります。) メッセージには、表示を更新するために必要な情報が含まれているか、「今が見頃です」という通知のいずれかです。

条件コードを使用する場合、処理スレッドは、条件を通知した後、更新スレッド用に大きなウィンドウを開くためにロックを再取得する前に、おそらく譲歩する必要があります。

于 2013-04-05T15:36:52.537 に答える
1

私が見ているように、ミューテックスの原則は公平性ではなく、正しさです。ミューテックス自体はスケジューラを制御できません。私を悩ませているのは、このような粗粒度のロックを使用する 2 つのスレッドを作成することを選択した理由です。理論的には、2 つのことを並行して実行していますが、実際にはそれらを相互依存/シリアルにしています。

ピートのアイデアはずっと良く (これらの描画と更新を実行する 1 つの関数)、競合と公平性についてそれほど心配する必要なく、各内部関数内でスレッドを使用できます。

2 つのスレッドを並行して実行したい場合は、いくつかのヒントを提供できます。

  • アトミックを使用してスピンロックし、ミューテックスを忘れます。
  • 実装定義の土地に入り、スレッドの優先順位を設定する、または
  • ロックをよりきめ細かくします。

残念ながら、これらはどちらも問題のないものではありません。

于 2013-04-05T17:17:02.330 に答える
0

Dale Wilson と FKaria によって提案されたように、条件を使用して問題を解決しましたが、反対方向に使用しました。そのため、プロセス スレッドは一時停止フラグをチェックし、設定されている場合は状態を待機して、ロックを解放します。表示スレッドは一時停止フラグを制御し、条件を通じて通知することでプロセス スレッドを再開します。コード: (コードはほとんど同じです。新しい行を でマークしました//New)

#include <boost/thread.hpp>
#include <boost/thread/condition.hpp>
#include <iostream>

using namespace std;
using namespace boost;

mutex mut;
condition cond;

volatile bool shouldPause = false; //New

void process() {
        double start = time(0);
        while(1) {
                unique_lock<mutex> lock(mut);

                if(shouldPause) cond.wait(mut); //New

                this_thread::sleep(posix_time::milliseconds(10));
                std::cout<<".";
                if(time(0)>start+10) break;
        }
}

int main() {

        thread t(process);

        while(!t.timed_join(posix_time::seconds(1))) {
                posix_time::ptime mst1 = posix_time::microsec_clock::local_time();
                cout<<endl<<"attempting to lock"<<endl;
                cout.flush();
                shouldPause = true; // New
                unique_lock<mutex> lock(mut);

                posix_time::ptime mst2 = posix_time::microsec_clock::local_time();
                posix_time::time_duration msdiff = mst2 - mst1;
                cout << std::endl<<"acquired lock in: "<<msdiff.total_milliseconds() << endl;
                cout.flush();

                shouldPause = false; // New
                cond.notify_all(); // New
        }

}

これで、出力は正確に希望どおりになりました。

...................................................................................................
attempting to lock
.
acquired lock in: 9
...................................................................................................
attempting to lock
.
acquired lock in: 8
...................................................................................................
attempting to lock
.
acquired lock in: 9
...................................................................................................
attempting to lock
.
acquired lock in: 8
...................................................................................................
attempting to lock
.
acquired lock in: 9
...................................................................................................
attempting to lock
.
acquired lock in: 9
...................................................................................................
attempting to lock
.
acquired lock in: 9
...................................................................................................
attempting to lock
.
acquired lock in: 9
...................................................................................................
attempting to lock
.
acquired lock in: 8
...................................................................................................
attempting to lock
.
acquired lock in: 9
..........................
于 2013-04-06T06:12:13.817 に答える