Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
ManualResetEvent(从C#)在C+上的实现+;:如何避免比赛状态 我想了解更多关于多线程编程的知识,我认为在C++中实现一些C同步基本图元是一个很好的练习。 我已经开始了,到目前为止我已经做到了: class manual_reset_event { public: void wait_one() { if (cv_flag_.load() == false) { thread_local std::mutex mutex; std::unique_lock<std::mutex> lock(mutex); cond_var_.wait(lock, [this]() { return cv_flag_.load(); }); } } void set() { cv_flag_.store(true); cond_var_.notify_all(); } void reset() { cv_flag_.store(false); } private: std::condition_variable cond_var_; std::atomic<bool> cv_flag_; }; 类手动重置事件 { 公众: void wait_one() { 如果(cv_标志加载()==false) { 线程\本地标准::互斥互斥; std::唯一锁(互斥锁); cond_var_uu.wait(lock,[this](){return cv_uflag_uu.load();}); } } 空集() { cv_标志_.存储(真); 条件变量通知所有(); } 无效重置() { cv_标志_.存储(假); } 私人: std::条件变量cond\u var; 标准::原子cv_标志u; };_C++_Multithreading_C++11 - Fatal编程技术网

ManualResetEvent(从C#)在C+上的实现+;:如何避免比赛状态 我想了解更多关于多线程编程的知识,我认为在C++中实现一些C同步基本图元是一个很好的练习。 我已经开始了,到目前为止我已经做到了: class manual_reset_event { public: void wait_one() { if (cv_flag_.load() == false) { thread_local std::mutex mutex; std::unique_lock<std::mutex> lock(mutex); cond_var_.wait(lock, [this]() { return cv_flag_.load(); }); } } void set() { cv_flag_.store(true); cond_var_.notify_all(); } void reset() { cv_flag_.store(false); } private: std::condition_variable cond_var_; std::atomic<bool> cv_flag_; }; 类手动重置事件 { 公众: void wait_one() { 如果(cv_标志加载()==false) { 线程\本地标准::互斥互斥; std::唯一锁(互斥锁); cond_var_uu.wait(lock,[this](){return cv_uflag_uu.load();}); } } 空集() { cv_标志_.存储(真); 条件变量通知所有(); } 无效重置() { cv_标志_.存储(假); } 私人: std::条件变量cond\u var; 标准::原子cv_标志u; };

ManualResetEvent(从C#)在C+上的实现+;:如何避免比赛状态 我想了解更多关于多线程编程的知识,我认为在C++中实现一些C同步基本图元是一个很好的练习。 我已经开始了,到目前为止我已经做到了: class manual_reset_event { public: void wait_one() { if (cv_flag_.load() == false) { thread_local std::mutex mutex; std::unique_lock<std::mutex> lock(mutex); cond_var_.wait(lock, [this]() { return cv_flag_.load(); }); } } void set() { cv_flag_.store(true); cond_var_.notify_all(); } void reset() { cv_flag_.store(false); } private: std::condition_variable cond_var_; std::atomic<bool> cv_flag_; }; 类手动重置事件 { 公众: void wait_one() { 如果(cv_标志加载()==false) { 线程\本地标准::互斥互斥; std::唯一锁(互斥锁); cond_var_uu.wait(lock,[this](){return cv_uflag_uu.load();}); } } 空集() { cv_标志_.存储(真); 条件变量通知所有(); } 无效重置() { cv_标志_.存储(假); } 私人: std::条件变量cond\u var; 标准::原子cv_标志u; };,c++,multithreading,c++11,C++,Multithreading,C++11,但是,这里有一个竞争条件:可以在一个线程上调用wait_one(),通过if(cv_标志)检查,然后从另一个线程调用set。这将导致wait_one()等待,即使cv_flag_uu现在为true。 我可以通过在等待、设置和重置上使用锁来解决这个问题。 我想我也可以通过在wait_one()上的cond_var.wait()之后立即调用cond_var.notify_all()来解决这个问题,但我认为这不是一个好主意(尽管可能我错了)。 我想知道是否还有其他方法(甚至可能是完全不同的方法,不使用

但是,这里有一个竞争条件:可以在一个线程上调用wait_one(),通过if(cv_标志)检查,然后从另一个线程调用set。这将导致wait_one()等待,即使cv_flag_uu现在为true。
我可以通过在等待、设置和重置上使用锁来解决这个问题。
我想我也可以通过在wait_one()上的cond_var.wait()之后立即调用cond_var.notify_all()来解决这个问题,但我认为这不是一个好主意(尽管可能我错了)。

我想知道是否还有其他方法(甚至可能是完全不同的方法,不使用条件变量)可以在这里避免这种竞争条件。

在大多数情况下,最简单的方法是使用顺序将对象内部与互斥体联系起来,而忽略原子。只需确保对数据的所有访问都受到锁的保护

如果只存储一个位,则在随后快速执行
设置
重置
时,可能会导致唤醒丢失,因为等待的线程只有在
重置
完成后才会安排。为了解决这个问题,我将使用计数器。计数器的最低位是其“打开”状态。该状态的每一次更改都以增量的形式实现。我使用64位计数器以防万一。32位不太可能是不够的,即使它可能在长时间运行的程序中循环使用

class manual_reset_event
{
public:
    void wait_one()
    {
        std::unique_lock<std::mutex> lock(mutex_);
        uint64_t initial_value = value_;
        if(initial_value & 1)
        {
            return;
        }
        while (value_ == initial_value)
        {
            signalled_.wait(lock);
        }
    }

    void set()
    {
        std::unique_lock<std::mutex> lock(mutex);
        if((value_ & 1) == 0)
        {
            value_++;
            lock.release(); // optimization
            signalled_.notify_all();
        }
    }

    void reset()
    {
        std::unique_lock<std::mutex> lock(mutex);
        if(value_ & 1)
        {
            value_++;
        }
    }

private:
    std::mutex mutex_;
    std::condition_variable signalled_;
    uint64_t value_;
};
类手动重置事件
{
公众:
void wait_one()
{
std::唯一锁(互斥锁);
uint64\u t初始值=值;
if(初始值&1)
{
返回;
}
while(值=初始值)
{
信号等待(锁定);
}
}
空集()
{
std::唯一锁(互斥锁);
如果((值_&1)==0)
{
值uz++;
lock.release();//优化
发出信号通知所有人();
}
}
无效重置()
{
std::唯一锁(互斥锁);
如果(值u1)
{
值uz++;
}
}
私人:
std::mutex mutex;
std::条件变量信号;
uint64_t值;
};

如果你坚持避免不必要的锁使用,你可以使用原子,但是解决方案有些棘手,因为有更多的顺序要考虑。

class manual_reset_event
{
public:
    void wait_one()
    {
        uint64_t initial_value = value_;
        if(initial_value & 1)
        {
            return;
        }
        std::unique_lock<std::mutex> lock(mutex_);
        while (value_ == initial_value)
        { // !
            signalled_.wait(lock);
        }
    }

    void set()
    {
        uint64_t initial_value = value_;
        if(initial_value & 1)
        {
            return;
        }
        std::unique_lock<std::mutex> lock(mutex_);
        // Still need lock to prevent lost wakeup if atomic change happens when
        // other thread is on "// !" line.
        if(value.compare_exchange_strong(initial_value, initial_value + 1)) {
        // One strong attempt is enough. If it fails than someone else must have
        // succeeded. It's as if these two set() operations happened at the same time.
            lock.release();
            signalled_.notify_all();
        }
    }

    void reset()
    {
        uint64_t initial_value = value_;
        if((initial_value & 1) == 0)
        {
            return;
        }
        std::unique_lock<std::mutex> lock(mutex_);
        value.compare_exchange_strong(initial_value, initial_value + 1);
    }

private:
    std::mutex mutex_;
    std::condition_variable signalled_;
    std::atomic<uint64_t> value_;
};
类手动重置事件
{
公众:
void wait_one()
{
uint64\u t初始值=值;
if(初始值&1)
{
返回;
}
std::唯一锁(互斥锁);
while(值=初始值)
{ // !
信号等待(锁定);
}
}
空集()
{
uint64\u t初始值=值;
if(初始值&1)
{
返回;
}
std::唯一锁(互斥锁);
//仍然需要锁定,以防止在发生原子更改时丢失唤醒
//其他线程位于“/!”行上。
if(值比较交换强(初始值,初始值+1)){
//一次强有力的尝试就足够了。如果失败了,那一定是别人干的
//成功。就好像这两个set()操作同时发生一样。
锁定。释放();
发出信号通知所有人();
}
}
无效重置()
{
uint64\u t初始值=值;
如果((初始_值&1)==0)
{
返回;
}
std::唯一锁(互斥锁);
值。比较交换强(初始值,初始值+1);
}
私人:
std::mutex mutex;
std::条件变量信号;
std::原子值;
};

一个可能的实现-保留等待事件线程的列表。对于
手动重置\u事件的保护状态,可以使用
std::mutex
。当线程开始等待时,他检查事件的状态,若并没有发出信号,则在列表中插入self“wait block”。这是在受公共对象互斥体保护的“临界区”内完成的。然后,若我们需要等待事件(当且仅当我们插入self-to-wait列表时)-开始等待等待块。但在此之前从“关键部分”退出非常重要,甚至在等待结束后也不会临时获得它。另一方面,线程设置等待线程的事件-获取列表,然后通知所有等待线程(在退出关键部分后),或者可能只通知单个等待线程,首先开始等待。因此,我们可以实现手动重新发送事件逻辑(当所有等待的线程同时唤醒时)或自动重置事件逻辑-当只有一个线程将被唤醒时,事件将再次重置(实际上根本没有设置为信号状态。仅当不再有等待的线程时-事件发出信号时)

class manual_reset_event : std::mutex
{
    struct WaitBlock : public std::condition_variable, std::mutex  
    {
        WaitBlock(WaitBlock* next) : next(next), signaled(false) {}

        WaitBlock* next;
        volatile bool signaled;

        void Wait()
        {
            // synchronization point with Wake()
            std::unique_lock<std::mutex> lock(*this);

            while (!signaled)
            {
                // notify_one() yet not called
                wait(lock);
            }
        }

        void Wake()
        {
            {
                // synchronization point with Wait()
                std::lock_guard<std::mutex> lock(*this);
                signaled = true;
            }
            notify_one();
        }
    };

    WaitBlock* _head;
    volatile bool _signaled;

public:

    manual_reset_event(bool signaled = false) : _signaled(signaled), _head(0) { }

    void wait()
    {
        lock();//++ protect object state

        WaitBlock wb(_head);

        bool inserted = false;

        if (!_signaled)
        {
            _head = &wb;
            inserted = true;
        }

        unlock();//-- protect object state

        if (inserted)
        {
            wb.Wait();
        }
    }

    // manual reset logic
    void set_all() 
    {
        WaitBlock* last, *head = 0;

        lock();//++ protect object state
        head = _head, _signaled = true;
        unlock();//-- protect object state

        while (last = head)
        {
            head = head->next;
            last->Wake();
        }
    }

    // auto reset logic - only one thread will be signaled, event auto reset
    void set_single()  
    {
        WaitBlock* last = 0;

        lock();//++ protect object state

        if (!_signaled)
        {
            if (last = _head)
            {
                // wake first waiting thread

                WaitBlock* prev = 0, *pwb;

                while (pwb = last->next)
                {
                    prev = last, last = pwb;
                }

                (prev ? prev->next : _head) = 0;

            }
            else
            {
                // nobody wait
                _signaled = true;
            }
        }
        unlock();//-- protect object state

        if (last)
        {
            last->Wake();
        }
    }

    void reset()
    {
        _signaled = false;
    }
};
类手动重置事件:std::mutex
{
结构WaitBlock:public std::condition_变量,std::mutex
{
WaitBlock(WaitBlock*next):next(next),有信号(false){}
WaitBlock*下一步;
挥发性bool信号;
无效等待()
{
//与Wake()的同步点
std::唯一锁(*此);
当(!发出信号)
{
//notify_one()尚未调用