Проблема с добавлением std::condition_variable.wait() для второй std::condition_variable
Если я добавляю в функцию wait для другой переменной после notfy_one для первой cv, первая перестает получать уведомление.
Здесь работает
#include <iostream>
#include <map>
#include <thread>
#include <chrono>
#include <string>
#include <mutex>
#include <condition_variable>
struct user{
std::unique_ptr<std::mutex> recv_mu;
std::unique_ptr<std::condition_variable> recv_cv;
std::unique_ptr<std::mutex> send_mu;
std::unique_ptr<std::condition_variable> send_cv;
std::string str_data;
bool shut_down{};
};
std::condition_variable cv1;
std::mutex mu;
std::map<std::string, user> users;
void TCPRecvThread() {
std::cout << "\nrecvThread started";
std::mutex* recv_mu = users["biba"].recv_mu.get();
std::condition_variable* recv_cv = users["biba"].recv_cv.get();
std::mutex* send_mu = users["biba"].send_mu.get();
std::condition_variable* send_cv = users["biba"].send_cv.get();
std::unique_lock<std::mutex> send_lk(*send_mu);
send_lk.unlock();
send_cv->notify_one();
send_lk.lock();
std::cout << "\nnotified sendThread";
std::this_thread::sleep_for(std::chrono::seconds(3));
std::unique_lock<std::mutex> recv_lk(*recv_mu);
//recv_cv->wait(recv_lk); проблема здесь
}
void TCPSendThread() {
std::cout << "\nsendThread started";
std::mutex* send_mu = users["biba"].send_mu.get();
std::condition_variable* send_cv = users["biba"].send_cv.get();
std::mutex* recv_mu = users["biba"].recv_mu.get();
std::condition_variable* recv_cv = users["biba"].recv_cv.get();
std::unique_lock<std::mutex> send_lk(*send_mu);
std::cout << "\nwaiting for notify";
send_cv->wait(send_lk);
std::cout << "\nrecieved a notify from recvThread";
}
int main() {
std::string str = "";
users["biba"] = { std::make_unique<std::mutex>(), std::make_unique<std::condition_variable>(), std::make_unique<std::mutex>(), std::make_unique<std::condition_variable>(), str, false };
std::thread send_th(TCPSendThread);
send_th.detach();
std::this_thread::sleep_for(std::chrono::seconds(1));
std::thread recv_th(TCPRecvThread);
recv_th.detach();
while (true) {
}
return 0;
}
А здесь нет
#include <iostream>
#include <map>
#include <thread>
#include <chrono>
#include <string>
#include <mutex>
#include <condition_variable>
struct user{
std::unique_ptr<std::mutex> recv_mu;
std::unique_ptr<std::condition_variable> recv_cv;
std::unique_ptr<std::mutex> send_mu;
std::unique_ptr<std::condition_variable> send_cv;
std::string str_data;
bool shut_down{};
};
std::condition_variable cv1;
std::mutex mu;
std::map<std::string, user> users;
void TCPRecvThread() {
std::cout << "\nrecvThread started";
std::mutex* recv_mu = users["biba"].recv_mu.get();
std::condition_variable* recv_cv = users["biba"].recv_cv.get();
std::mutex* send_mu = users["biba"].send_mu.get();
std::condition_variable* send_cv = users["biba"].send_cv.get();
std::unique_lock<std::mutex> send_lk(*send_mu);
send_lk.unlock();
send_cv->notify_one();
send_lk.lock();
std::cout << "\nnotified sendThread";
std::this_thread::sleep_for(std::chrono::seconds(3));
std::unique_lock<std::mutex> recv_lk(*recv_mu);
recv_cv->wait(recv_lk); //проблема здесь
}
void TCPSendThread() {
std::cout << "\nsendThread started";
std::mutex* send_mu = users["biba"].send_mu.get();
std::condition_variable* send_cv = users["biba"].send_cv.get();
std::mutex* recv_mu = users["biba"].recv_mu.get();
std::condition_variable* recv_cv = users["biba"].recv_cv.get();
std::unique_lock<std::mutex> send_lk(*send_mu);
std::cout << "\nwaiting for notify";
send_cv->wait(send_lk);
std::cout << "\nrecieved a notify from recvThread";
}
int main() {
std::string str = "";
users["biba"] = { std::make_unique<std::mutex>(), std::make_unique<std::condition_variable>(), std::make_unique<std::mutex>(), std::make_unique<std::condition_variable>(), str, false };
std::thread send_th(TCPSendThread);
send_th.detach();
std::this_thread::sleep_for(std::chrono::seconds(1));
std::thread recv_th(TCPRecvThread);
recv_th.detach();
while (true) {
}
return 0;
}
В чем здесь может быть проблема?
UPD
В моем случае помогло удаление std::unique_lock<std::mutex> send_lk(*send_mu) и всех последующих операций с ним из функции TCPRecvThread(). Как send_lk.unlock() и send_lk.lock() соответственно до и после send_cv->notify_one() могли повлиять на send_cv->wait()?
Ответы (1 шт):
Замочек sendmu установленный вручную в TCPRecvThread() не даёт процессу TCPSendThread() взять этот замок себе.
TCPRecvThread() TCPSendThread()
lock sendmu
wait , unlock sendmu
lock sendmu
unlock sendmu
notify_one не успеваю залочить sendmu ...
lock sendmu
lock recv_mu
wait , unlock recv_mu
чтобы очнуться, надо залочить
sendmu для себя, а он вечно заперт
После notify_one вы сразу-же залочили sendmu. Не хватило времени, чтобы другой процесс взял sendmu себе. Можно после notify_one добавить паузу чтобы сразу не лочить sendmu. Или даже просто его не закрывать второй раз.