4

学習課題として、C++ 標準で提供されている およびその他のいくつかのものSemaphoreを使用してクラスを作成しようとしています。std::mutexセマフォは必要な数だけ許可するreadLock()必要がありwriteLock()ますが、すべての読み取りがロック解除された後にのみ取得できます。

//Semaphore.h
#include <mutex>
#include <condition_variable>

class Semaphore{
public:
    Semaphore();
    void readLock(); //increments the internal counter
    void readUnlock(); //decrements the internal counter
    void writeLock(); //obtains sole ownership.  must wait for count==0 first
    void writeUnlock(); //releases sole ownership.
    int count; //public for debugging
private:
    std::mutex latch;
    std::unique_lock<std::mutex> lk;
    std::condition_variable cv;
};

//Semaphore.cpp
#include "Semaphore.h"
#include <condition_variable>
#include <iostream>

using namespace std;

Semaphore::Semaphore() : lk(latch,std::defer_lock) { count=0; }
void Semaphore::readLock(){ 
    latch.lock();
    ++count;
    latch.unlock();
    cv.notify_all(); //not sure if this needs to be here?
}
void Semaphore::readUnlock(){
    latch.lock();
    --count;
    latch.unlock();
    cv.notify_all(); //not sure if this needs to be here?
}
void Semaphore::writeLock(){
    cv.wait(lk,[this](){ return count==0; }); //why can't std::mutex be used here?
}
void Semaphore::writeUnlock(){ 
    lk.unlock();
    cv.notify_all();
}

私のテスト プログラムはwriteLock()、セマフォを処理し、一連のスレッドを開始してから、セマフォを解放します。その直後に、メイン スレッドはwriteLock()セマフォを再試行します。アイデアは、セマフォがロック解除されると、スレッドがreadLock()それを行い、すべてが終了するまでメインスレッドが何もできないようにするというものです。それらがすべて終了してセマフォを解放すると、メインスレッドは再びアクセスを取得できます。これは必ずしも起こるとは限りませんが、私が探しているケースの 1 つです。

//Main.cpp
#include <iostream>
#include <thread>
#include "Semaphore.h"

using namespace std;

Semaphore s;

void foo(int n){
    cout << "Thread Start" << endl;
    s.readLock();
    this_thread::sleep_for(chrono::seconds(n));
    cout << "Thread End" << endl;
    s.readUnlock();
}

int main(){
    std::srand(458279);
    cout << "App Launch" << endl;
    thread a(foo,rand()%10),b(foo,rand()%10),c(foo,rand()%10),d(foo,rand()%10);

    s.writeLock();
    cout << "Main has it" << endl;

    a.detach();
    b.detach();
    c.detach();
    d.detach();

    this_thread::sleep_for(chrono::seconds(2));
    cout << "Main released it" << endl;
    s.writeUnlock();

    s.writeLock();
    cout << "Main has it " << s.count << endl;
    this_thread::sleep_for(chrono::seconds(2));
    cout << "Main released it" << endl;
    s.writeUnlock();

    cout << "App End" << endl;

    system("pause"); //windows, sorry
    return 0;
}

プログラムは、「所有されていないミューテックスのロック解除」という例外をスローします。writeLock()エラーはまたはにあると思いますが、writeUnlock()よくわかりません。誰かが私を正しい方向に向けることができますか?

編集:コンストラクターでstd::defer_lock初期化するときに欠落がありましたがlk、発生していたエラーは修正されませんでした。コメントで述べたように、これはセマフォではなく、混乱をお詫びします。問題を繰り返すために、これが私が得た出力です(括弧内のものは単なる私のコメントであり、実際には出力にはありません):

App Launch
Thread Start
Thread Start
Main has it
Thread Start
Thread Start
Thread End (what?)
Main released it
f:\dd\vctools\crt_bld\self_x86\crt\src\thr\mutex.c(131): unlock of unowned mutex
Thread End
Thread End
Thread End
4

1 に答える 1

3

これは間違いなく「セマフォ」ではありません。

コンストラクターはすぐSemaphoreにロックを取得し、 2 回ロックを解除します。これは、 の呼び出しと次の呼び出しがロックされていないミューテックスを使用して条件変数を待機しようとするためです。これは未定義の動作です。、これも未定義の動作です。latchwriteUnlock()lk.unlock()writeLock()writeUnlock()

コンストラクターがミューテックスをすぐにロックする必要がありますか? std::defer_lockコンストラクターで使用してから、ミューテックスをロックしたいと思いますwriteLock()

于 2013-09-18T18:03:38.140 に答える