Наряду с основным потоком у меня есть еще один поток, который получает данные для записи их в файл.
std::queue<std::vector<int>> dataQueue;
std::mutex mutex;
void setData(const std::vector<int>& data) {
std::lock_guard<std::mutex> lock(mutex);
dataQueue.push(data);
}
void write(const std::string& fileName) {
std::unique_ptr<std::ostream> ofs = std::unique_ptr<std::ostream>(new zstr::ofstream(fileName));
while (store) {
std::lock_guard<std::mutex> lock(mutex);
while (!dataQueue.empty()) {
std::vector<int>& data= dataQueue.front();
ofs->write(reinterpret_cast<char*>(data.data()), sizeof(data[0])*data.size());
dataQueue.pop();
}
}
}
}
setData
используется основным потоком, а write
фактически является записывающим потоком. Я использую std::lock_quard
, чтобы избежать конфликта памяти, но при блокировке записывающего потока он замедляет основной поток, так как должен ждать, пока очередь не будет разблокирована. Но я думаю, что могу избежать этого, поскольку потоки никогда не действуют на один и тот же элемент очереди в одно и то же время.
Так что я хотел бы сделать это без блокировки, но я не совсем понимаю, как мне это реализовать. Я имею в виду, как я могу сделать это, ничего не блокируя? более того, если записывающий поток работает быстрее, чем основной, большую часть времени очередь может быть пустой, поэтому он должен каким-то образом ждать новых данных, а не бесконечно циклически проверять наличие непустой очереди.
EDIT : я изменил простой std::lock_guard
на std::cond_variable
, чтобы он мог ждать, когда очередь пуста. Но основной поток все еще может быть заблокирован, так как, когда разрешен cvQeue.wait(.)
, он снова получает блокировку. более того, что, если основной поток выполняет cvQueue.notify_one()
, но поток записи не ожидает?
std::queue<std::vector<int>> dataQueue;
std::mutex mutex;
std::condition_variable cvQueue;
void setData(const std::vector<int>& data) {
std::unique_lock<std::mutex> lock(mutex);
dataQueue.push(data);
cvQueue.notify_one();
}
void write(const std::string& fileName) {
std::unique_ptr<std::ostream> ofs = std::unique_ptr<std::ostream>(new zstr::ofstream(fileName));
while (store) {
std::lock_guard<std::mutex> lock(mutex);
while (!dataQueue.empty()) {
std::unique_lock<std::mutex> lock(mutex);
cvQueue.wait(lock);
ofs->write(reinterpret_cast<char*>(data.data()), sizeof(data[0])*data.size());
dataQueue.pop();
}
}
}
}