Сборка клиента SignalR C ++ с использованием Visual Studio 2013, я начинаю с рабочего примера кода из пакета NuGet Microsoft.AspNet.SignalR.Client.Cpp.v120.WinDesktop, источник Вот
Рассматривая исходный код библиотеки, мне кажется, что процессы обработки событий основаны на Параллельное время выполнения (pplx :: task), которая опирается на Особенности C ++ 11
void chat(const utility::string_t& name)
{
signalr::hub_connection connection{ U("https://testsite") };
auto proxy = connection.create_hub_proxy(U("ChatHub"));
proxy.on(U("broadcastMessage"), [](const web::json::value& m)
{
ucout << std::endl << m.at(0).as_string() << U(" wrote:") << m.at(1).as_string() << std::endl << U("Enter your message: ");
});
connection.start()
.then([proxy, name]()
{
for (;;)
{
utility::string_t message;
std::getline(ucin, message);
if (message == U(":q"))
{
break;
}
send_message(proxy, name, message);
}
})
.then([&connection]() // fine to capture by reference - we are blocking so it is guaranteed to be valid
{
return connection.stop();
})
.then([](pplx::task<void> stop_task)
{
try
{
stop_task.get();
ucout << U("connection stopped successfully") << std::endl;
}
catch (const std::exception &e)
{
ucout << U("exception when starting or stopping connection: ") << e.what() << std::endl;
}
}).get();
}
Я хочу исключить компонент «пользовательский ввод»; и вместо этого выйти из цикла, когда было получено определенное «broadcastMessage».
Если я заменю цикл for оператором sleep, событие broadcastMessage перестанет срабатывать.
Если я использую цикл for без getline, когда все готово, устанавливаю bComplete в true, это работает так, как я хочу, но вызывает высокую загрузку ЦП (очевидно)
for (;;)
{
if (bComplete) break;
}
В идеале я хочу, чтобы соединение установилось, а затем просто подождать пока сигналы событий broadcastMessage закроют соединение.
Кроме того, функция «чат» не должна возвращаться, пока соединение не будет закрыто.
Я могу видеть в ваш ответ что вы уже обнаружили Объекты событий Windows; однако, если вы искали решение, не зависящее от платформы C ++ 11, подумайте std::condition_variable
!
unsigned int accountAmount;
std::mutex mx;
std::condition_variable cv;
void depositMoney()
{
// go to the bank etc...
// wait in line...
{
std::unique_lock<std::mutex> lock(mx);
std::cout << "Depositing money" << std::endl;
accountAmount += 5000;
}
// Notify others we're finished
cv.notify_all();
}
void withdrawMoney()
{
std::unique_lock<std::mutex> lock(mx);
// Wait until we know the money is there
cv.wait(lock);
std::cout << "Withdrawing money" << std::endl;
accountAmount -= 2000;
}
int main()
{
accountAmount = 0;
std::thread deposit(&depositMoney);
std::thread withdraw(&withdrawMoney);
deposit.join();
withdraw.join();
std::cout << "All transactions processed. Final amount: " << accountAmount << std::endl;
return 0;
}
В этом примере мы создаем два потока: один для ввода денег на счет и один для снятия денег. Поскольку поток может вывести деньги для запуска в первую очередь, особенно потому, что с depositMoney()
Нам нужно подождать, пока мы не узнаем, что деньги есть. Перед тем как получить доступ к деньгам, мы блокируем нашу ветку, а затем сообщаем condition_variable
что мы ждем condition_variable
разблокирует поток, и как только деньги будут внесены на notify_all()
называется, мы будем снова пробуждены, чтобы закончить обработку нашей логики.
Обратите внимание, что можно сделать то же самое, используя Объекты событий Windows. Вместо std::condition_variable::wait()
а также std::condition_variable::notify_all()
вы бы использовали SetEvent()
а также WaitForSingleObject()
, Это не зависит от платформы.
Я получил это работает с помощью WinAPI WaitForSingleObject:
HANDLE hEvent;
void chat(const utility::string_t& name)
{
signalr::hub_connection connection{ U("https://testsite") };
auto proxy = connection.create_hub_proxy(U("ChatHub"));
proxy.on(U("broadcastMessage"), [](const web::json::value& m)
{
ucout << std::endl << m.at(0).as_string() << U(" wrote:") << m.at(1).as_string() << std::endl;
if (m.at(1).as_string() == L"quit")
{
SetEvent(hEvent);
}
});
hEvent = CreateEvent(0, TRUE, FALSE, 0);
connection.start()
.then([proxy, name]()
{
WaitForSingleObject(hEvent, INFINITE);
})
.then([&connection]() // fine to capture by reference - we are blocking so it is guaranteed to be valid
{
return connection.stop();
})
.then([](pplx::task<void> stop_task)
{
try
{
stop_task.get();
ucout << U("connection stopped successfully") << std::endl;
}
catch (const std::exception &e)
{
ucout << U("exception when starting or stopping connection: ") << e.what() << std::endl;
}`enter code here`
}).get();
}