簡體   English   中英

如何重置std :: condition_variable

[英]how to reset std::condition_variable

我正在嘗試使用條件變量來觸發第二個線程在一定數量的緩沖區處於雙端隊列之后進行一些工作。

  • main()正在緊密和時間敏感的循環中讀取ADC數據
  • main()將緩沖區添加到雙端隊列(由線程池管理器處理)
  • 雙端隊列的深度是可變的,因此無法在main()中測試深度> = 4,然后再調用notify_one(即:在繁重的處理時間中,雙端隊列的深度可能多達200或300個緩沖區,或者少至光處理過程中的4個)
  • thrd()永遠不需要發信號main()

我的問題是在thrd()中,在獲得信號和緩沖區<4之后,它會循環返回while循環並立即再次獲得條件。 有沒有辦法重置簡歷?

deque<int> vbufs;
std::mutex thrdLock;
void thrd()
{
    while (true) {
        cout << "thrd() waiting for lock\n";
        std::unique_lock < std::mutex > lock(thrdLock);
        cout << "thrd() waiting for condition\n";
        cv.wait(lock, []{ return (vbufs.size() > 0); });
        thrdLock.unlock();
        cout << "thrd() condition set\n";

        if (vbufs.size() >= 4) {    // pretend to do something with 4 buffers and remove them
            std::lock_guard < std::mutex > lock(thrdLock);
            vbufs.pop_front();
            vbufs.pop_front();
            vbufs.pop_front();
            vbufs.pop_front();
            cout << "thrd() reducing buffers:" << vbufs.size() << endl;
        }
    }
}

int main(int argc, char* argv[]) {
    std::thread t1(thrd);
    int tctr = 0;

    while (true) {
        usleep(1000);

        {
            cout << "main() waiting for lock\n";
            std::lock_guard < std::mutex > lock(thrdLock);
            vbufs.push_back(++tctr);
            cout << "main() incremented buffers:" << vbufs.size() << endl;
        }
        cv.notify_one();
    }
    return 0;
}

您不能重置條件變量; 這沒有任何意義-通知它不會更改其狀態,因此無需重置。 收到通知后,只能喚醒已經等待的線程。 如果該線程然后再次等待,它將不會繼續,直到重新通知條件變量。

如果您只想在有四個或更多緩沖區的情況下進行工作,是否不應該這樣更改等待時間?

cv.wait(lock, []{ return (vbufs.size() >= 4); });

更重要的是,您可能vbufs同時從兩個不同的線程讀取和寫入vbufs您的if (vbufs.size() >= 4)發生在鎖之外,因此可能與對push_back的調用同時發生。 這導致不確定的行為,可能會解釋您所看到的。

我在程序中發現了兩個錯誤-此處已糾正:

注意:您直接解鎖互斥鎖而不是通過std::unique_lock解鎖的方式導致了數據爭用。

#include <iostream>
#include <deque>
#include <mutex>
#include <thread>
#include <chrono>
#include <condition_variable>

std::deque<int> vbufs;
std::mutex thrdLock;
std::condition_variable cv;

template<class...Ts>
void emit(Ts&&...ts)
{
    static std::mutex m;
    std::lock_guard<std::mutex> lg(m);
    using expand = int[];
    void(expand { 0, ((std::cout << std::forward<Ts>(ts)), 0)... });
}

void thrd()
{
    while (true) {
        emit("thrd() waiting for lock\n");
        std::unique_lock < std::mutex > lock(thrdLock);
        emit("thrd() waiting for condition\n");
        cv.wait(lock, []{ return vbufs.size() >= 4; });
        emit("thrd() condition set\n");
        auto a = vbufs.front(); vbufs.pop_front();
        auto b = vbufs.front(); vbufs.pop_front();
        auto c = vbufs.front(); vbufs.pop_front();
        auto d = vbufs.front(); vbufs.pop_front();
        emit("thrd() reducing buffers:", vbufs.size(), '\n');
        lock.unlock();
        emit(a, ' ', b, ' ', c, ' ', d, '\n');
    }
}

int main(int argc, char* argv[]) {
    std::thread t1(thrd);
    int tctr = 0;

    while (true) {
        std::this_thread::sleep_for(std::chrono::microseconds(10));

        {
            emit("main() waiting for lock\n");
            std::lock_guard < std::mutex > lock(thrdLock);
            vbufs.push_back(++tctr);
            emit("main() incremented buffers:", vbufs.size(), '\n');
        }
        cv.notify_one();
    }
    t1.join(); // un-necessary in this case, but...
    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM