1

我有个问题。我想为我的程序使用互斥锁。所以发生的事情是这样的:我正在构造一个包含 std::timed_mutex 的对象。在创建时,此对象会锁定互斥锁,因为稍后应将其解锁。创建互斥锁的同一线程现在应该等待该互斥锁,而其他线程确实在后台工作。加入线程是没有选择的。

class A{
    std::timed_mutex mutex;
    A(){
        mutex.lock();
    }

    bool waitForIt(int timeout){
        if(mutex.try_lock_for(std::chrono::milliseconds(timeout))){
            mutex.unlock();
            return true;
        }else{
            return false;
        }
    }
}

当从同一个线程调用waitForIt时,程序只是通过并立即得到一个错误,完全忽略超时。(是的,它打算在之后解锁互斥锁。它应该模仿一个事件,这样每个等待的线程都会通过)

所以在文档中它说这个互斥锁具有非递归行为。但测试表明,例如,我可以从同一个线程多次使用 .lock() 而不会被阻塞。我也可以多次使用 try_lock_for 并且每次都正确!!!如果我曾经在 try_lock_fors 之前使用过锁,我总是会出错。可悲的是,我需要一些东西来阻止锁定互斥锁的同一线程。我不知道该用什么。我在linux上编程顺便说一句。所以也许有一个本地解决方案?

我也没有在标准库中找到信号量。我可以使用它来代替互斥锁。使用我自己的实现是可能的,但我不知道如何制作自己的信号量。有任何想法吗?

因为人们似乎不明白它不是那么简单:

class IObservable : public IInterface{
private:
    std::list<std::shared_ptr<IObserver>> observers;
public:
    virtual ~IObservable(){}

    void AddObserver(std::shared_ptr<IObserver> observer);
    void RemoveObserver(std::shared_ptr<IObserver> observer);
    void ClearObservers();
    void TellCompleted(bool wasCanceled = false, std::shared_ptr<void> status = 0);
    TYPEIDHASHFUNC(IObservable)
};

IObservable 是线程可以添加观察者的东西。从 IObservable 派生的事物在其操作结束时调用方法 TellCompleted。

class IObserver : public IInterface{
public:
    virtual ~IObserver(){}

    virtual CompleteResult Complete(bool wasCanceled, std::shared_ptr<void> status) = 0;
    virtual bool WaitForCompletion(int timeoutInMs) = 0;
    virtual bool IsCompleted() const = 0;
    virtual bool WasCanceled() const = 0;
    virtual std::shared_ptr<void> GetStatus() const = 0;
    virtual void Reset() = 0;
    TYPEIDHASHFUNC(IObserver)
};

IObserver 是可以添加到 IObservable 的观察者。如果 IObservable 完成,则在添加到 observable 的每个观察者上调用 Complete 方法

class BasicObserver : public IObserver{
private:
    bool isCompleted;
    bool wasCanceled;
    CompleteResult completeResult;
    std::shared_ptr<void> status;
    std::timed_mutex mutex;
public:
    BasicObserver(CompleteResult completeResult);
    ~BasicObserver();

    CompleteResult Complete(bool wasCanceled, std::shared_ptr<void> status);
    bool WaitForCompletion(int timeoutInMs);
    bool IsCompleted() const;
    bool WasCanceled() const;
    std::shared_ptr<void> GetStatus() const;
    void Reset();
    TYPEIDHASHFUNC(BasicObserver)
};

这是观察者的一种实现。它持有互斥体并使用超时实现 WaitForCompletion。WaitForCompletion 应该阻塞。当调用完成时,它的互斥锁应该被解锁。当超时运行 WaitForCompletion 返回 false

BasicObserver::BasicObserver(CompleteResult completeResult):
    isCompleted(false),
    wasCanceled(false),
    completeResult(completeResult)
{
    std::thread createThread([this]{
        this->mutex.lock();
    });
    createThread.join();
}

BasicObserver::~BasicObserver(){
}

CompleteResult BasicObserver::Complete(bool wasCanceled, std::shared_ptr<void> status){
    this->wasCanceled = wasCanceled;
    this->status = status;
    isCompleted = true;
    mutex.unlock();
    return completeResult;
}

bool BasicObserver::WaitForCompletion(int timeoutInMs){
    std::chrono::milliseconds time(timeoutInMs);
    if(mutex.try_lock_for(time)){
        mutex.unlock();
        return true;
    }else{
        return false;
    }
}

bool BasicObserver::IsCompleted() const{
    return isCompleted;
}

bool BasicObserver::WasCanceled() const{
    return wasCanceled;
}

std::shared_ptr<void> BasicObserver::GetStatus() const{
    return status;
}

void BasicObserver::Reset(){
    isCompleted = false;
    wasCanceled = false;
    status = 0;
    std::chrono::milliseconds time(250);
    mutex.try_lock_for(time); //if this fails it might be already resetted
}

//编辑:通过使用信号量解决(来自 semaphore.h 的 sem_t)

4

2 回答 2

0

您可以使用 a condation_variable,特别是wait_untilwait_for

于 2014-02-28T00:20:37.150 回答
0

我会考虑重新设计您的锁定结构。为什么不让主线程持有锁,当事件 x 发生时你解锁它。如果您需要阻塞一段时间,我只会让线程休眠。让所有工作线程阻塞在互斥锁上尝试获取锁,如果它们需要同时运行,让它们在获取锁后立即释放锁。

也许使用第二个互斥锁来模拟事件 x。

我想从线程 1 设置锁,然后启动线程 2 执行某些操作(在这种情况下等待来自硬件的输入),然后等待线程 1 中的互斥锁。线程 2 然后在我按下开关时解锁互斥锁硬件。我使用某种观察者模式。所以我有一些可观察的东西,我添加了一个观察者(在这种情况下,A 类是观察者)。在某些时候,observable 会告诉所有添加的观察者它完成了任务,从而解锁了互斥锁。因为我们这里有硬件,所以可能是硬件锁定或传感器不起作用。所以我需要一个超时。– fredllll 3 分钟前

编辑- 也许这会工作?

在线程 2 获得该锁上的输入块之后,在线程 1 中保持锁。让线程 1 在超时持续时间后释放锁,可能会稍微休眠以允许线程通过然后再次获取锁。让线程 2 释放锁 1,然后在获取互斥锁 1 后开始阻塞第二个互斥锁,让硬件开关解锁互斥锁 2,这导致线程 2 锁定互斥锁 2,然后解锁互斥锁 2。让硬件开关再次获取互斥锁 2。

于 2014-02-28T00:28:38.130 回答