C++ 等待但允许事件触发
C++ Wait But Allow Events To Fire
使用 Visual Studio 2013 构建 SignalR C++ 客户端,我从 NuGet 包 Microsoft.AspNet.SignalR.Client.Cpp.v120.WinDesktop 中的工作示例代码开始, 来源 here
查看库源代码,在我看来,事件处理过程是基于 Concurrency Runtime (pplx::task) which relies on C++11 features
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();
}
我想删除 "user input" 组件;而是在收到特定 "broadcastMessage" 时退出循环。
如果我用睡眠语句替换 for 循环,broadcastMessage 事件将停止触发。
如果我在没有 getline 的情况下使用 for 循环,完成后将 bComplete 设置为 true,它会按我想要的方式工作,但会导致高 CPU 使用率(很明显)
for (;;)
{
if (bComplete) break;
}
理想情况下,我希望连接开始,然后等待 broadcastMessage 事件发出信号关闭连接。
此外,在连接关闭之前,"chat" 函数不应 return。
我使用 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();
}
我可以在 that you've already discovered Windows event objects; however, if you were looking for a C++11 platform-independent solution, consider 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 event objects 执行完全相同的操作。您将使用 SetEvent()
和 WaitForSingleObject()
,而不是 std::condition_variable::wait()
和 std::condition_variable::notify_all()
。不过这与平台无关。
使用 Visual Studio 2013 构建 SignalR C++ 客户端,我从 NuGet 包 Microsoft.AspNet.SignalR.Client.Cpp.v120.WinDesktop 中的工作示例代码开始, 来源 here
查看库源代码,在我看来,事件处理过程是基于 Concurrency Runtime (pplx::task) which relies on C++11 features
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();
}
我想删除 "user input" 组件;而是在收到特定 "broadcastMessage" 时退出循环。
如果我用睡眠语句替换 for 循环,broadcastMessage 事件将停止触发。
如果我在没有 getline 的情况下使用 for 循环,完成后将 bComplete 设置为 true,它会按我想要的方式工作,但会导致高 CPU 使用率(很明显)
for (;;)
{
if (bComplete) break;
}
理想情况下,我希望连接开始,然后等待 broadcastMessage 事件发出信号关闭连接。 此外,在连接关闭之前,"chat" 函数不应 return。
我使用 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();
}
我可以在 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 event objects 执行完全相同的操作。您将使用 SetEvent()
和 WaitForSingleObject()
,而不是 std::condition_variable::wait()
和 std::condition_variable::notify_all()
。不过这与平台无关。