C++ подождите, но разрешите запуск событий

При создании клиента SignalR C++ с использованием Visual Studio 2013 я начинаю с рабочего примера кода из пакета NuGet Microsoft.AspNet.SignalR.Client.Cpp.v120.WinDesktop, источник здесь

Рассматривая исходный код библиотеки, мне кажется, что процессы обработки событий основаны на среде выполнения Concurrency (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 закроют соединение. Кроме того, функция "чат" не должна возвращаться, пока соединение не будет закрыто.

2 ответа

Решение

В вашем ответе я вижу, что вы уже обнаружили объекты событий 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();
    }
Другие вопросы по тегам