繁体   English   中英

如何在Vector中插入conditional_variable对象?

[英]How to insert a conditional_variable object into a Vector?

conditional_variable不是CopyConstructible,MoveConstructible,CopyAssignable,MoveAssignable。

我们可以这样打电话吗

vector<conditional_variable> cond;

conditional_variable c1;
conditional_variable c2;
cond.push_back(c1);
cond.push_back(c2);

在这些情况下正确的方法是什么

您可以创建矢量,这些矢量可以默认构造,但不能通过使用带有size参数的构造函数进行复制或移动:

std::vector<std::condition_variable> cv_vec(20);

这样的向量无法增长,但可以通过pop_back()clear()缩小(但不能使用erase()resize() )。

另外,由于可以通过额外的间接级别解决所有问题,因此可以改为使用std::unique_ptr<std::condition_variable>的向量。

现在,为什么在地球上有人会想要为诸如condition_variable类的同步原语执行此操作,我不知道...

不,您不能,我建议您使用vector<unique_ptr<conditional_variable>> 然后,您可以分配一个新的conditional_variable并将其添加到向量中

通过让向量保存对象A_with_cv ,您可以将std::condition_variable转换为std::vector<A_with_cv> ,这些对象具有不复制成员std::condition_variable复制构造A_with_cv和复制赋值运算符。

这是一个例子:

// compile with: c++ -std=c++14 -o go main.cpp -pthread

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

class A {
public:
    A()                  {}
    A(int d) : data_{d}  {}

    int  data()          const { return data_; }
    void set_data(int d)       { data_ = d;    }
private:
    int data_{0};
};

class A_with_cv : public A {
public:
    A_with_cv(int d = 0) : A{d}
    {}

    A_with_cv(const A_with_cv &a) : A{static_cast<const A&>(a)} // don't copy cv_ !
    {}

    A_with_cv &operator=(const A_with_cv &other)
    {
        static_cast<A&>(*this) = static_cast<const A&>(other); // don't copy cv_ !
    }

    std::condition_variable       &cv()       { return cv_; };
    const std::condition_variable &cv() const { return cv_; };
private:
    std::condition_variable cv_;
};


struct Printer {
public:
    Printer(std::vector<A_with_cv> &vec) {
        initiate_print(vec);
    }

    void initiate_print(std::vector<A_with_cv> &vec) {
        for (auto it = vec.begin(); it != vec.end(); ) {
            auto &val_ref = *it;

            ++it; // increment
            if (it != vec.end()) {
                auto &next_ref = *it;
                th_vec_.push_back(std::thread(
                                              [&]() {
                                                  std::unique_lock<std::mutex> lk(mut_);
                                                  val_ref.cv().wait(lk);
                                                  std::cout << val_ref.data() << std::endl;
                                                  lk.unlock();
                                                  next_ref.cv().notify_one(); // notify next
                                              }));
            } else {
                th_vec_.push_back(std::thread(
                                              [&]() {
                                                  std::unique_lock<std::mutex> lk(mut_);
                                                  val_ref.cv().wait(lk);
                                                  std::cout << val_ref.data() << std::endl;
                                              }));
            }
        }
    }

    void wait_for_thread_completion() {
        for (auto &th : th_vec_) {
            th.join();
        }
    }
private:
    std::mutex mut_;
    std::vector<std::thread> th_vec_;
};


int main()
{
    std::vector<A_with_cv> vec;
    vec.push_back(A_with_cv(1));
    vec.push_back(A_with_cv(2));
    vec.push_back(A_with_cv(3));

    Printer printer(vec);

    std::this_thread::sleep_for(std::chrono::milliseconds{500});
    vec[0].cv().notify_one();

    printer.wait_for_thread_completion();
}

但是在使用向量时要非常小心。 向量可以重新分配元素,您可能会认为您正在通知condition_variable,但实际上它不再存在(例如,因为在此期间您做了一些push_backs,并且迭代器和对向量元素的引用已经无效)! 因此,为此,宁愿使用一个不会重新分配/无效std::list元素的容器(或-前提是您只在元素的正面或背面添加元素: std::deque )等,因为这样更安全!

使用此类容器时,不要重新分配/使元素无效,请确保使用emplace。 例:

#include <condition_variable>
#include <map>
#include <list>
#include <vector>
#include <deque>

int main()
{
    std::deque<std::condition_variable> deq;
    //deq.push_back(std::condition_variable());                 // does not work
    deq.emplace_back();

    std::list<std::condition_variable> li;
    //li.push_back(std::condition_variable());                  // does not work
    li.emplace_back();

    std::map<int, std::condition_variable> ma;
    //ma.insert( std::make_pair(1, std::condition_variable())); // does not work
    //ma.emplace(std::make_pair(1, std::condition_variable())); // does not work
    ma.emplace(std::piecewise_construct,
               std::forward_as_tuple(1),
               std::forward_as_tuple());

    return 0;
}

问题是, std::vector在内存中的某个地方分配了一个数组,并且如果该向量后来增长,则需要将该数组移到另一个位置。 因此,即使这段代码也无法编译:

std::vector<std::condition_variable> cvvector;
cvvector.emplace_back();

解决方案是使用功能更广泛的容器std::deque代替std::vector std::deque永远不会移动为其对象分配的实际存储。 尽管如此, std::deque通过[]运算符具有恒定的元素引用访问时间:

std::deque<std::condition_variable> cvvector;
cvvector.emplace_back();
cvvector.emplace_back();
std::condition_variable& cv = cvvector[1];

我称该容器仍为cvvector :只要您不使用cvvector::emplace_front()cvvector::pop_front() ,它的行为就象一个向量,而不是一个队列。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM