I have a C++ plugin I have written for a proprietary software which makes an asynchronous call to a function called OpenLibrary. To know when the library load has completed, I must register for a specific event. Then, when that event is triggered, an OnEvent routine is called. This logic is somewhat sterilized for proprietary reasons, but the asynchronous call and onEvent trigger works correctly. Unfortunately, since the OpenLibrary call is asynchronous, the loop is not blocked and continues without waiting for the EVENT_LIBRARY_LOADED event. I need to process the files serially.
...
void MyApp::main()
{
for(int i=0; i<total; ++i) {
pData->RegisterEvent( EVENT_LIBRARY_LOADED, this );
pData->OpenLibrary("c:/path/file.dat"); // asynchronous call
}
}
...
void MyApp::OnEvent( ID eventType )
{
if (eventType == EVENT_LIBRARY_LOADED) {
qDebug() << "Library load has completed";
}
}
...
The plugin requires VS2008 and also takes advantage of the Qt library.
I would like to create a function called waitForEvent, where subsequent code is blocked until the event has occurred then waitForEvent can return control back to the calling routines loop. This way, I can stay inside my main routines loop and simply wait for the event before continuing. Any suggestions appreciated.
UPDATE: I have tried both excellent suggestions below by Tas, but in either case, I get the same result. The WaitForSingleObject OR the condition_variable.wait BOTH prevent the EVENT_LIBRARY_LOADED event from triggering the OnEvent function from being called, which freezes the loop.
Any more suggestions appreciated.
If boost libraries are an option, use boost::condition_variable
You've already made it clear C++11 isn't an option (otherwise you could use std::condition_variable). boost::condition_variable will accomplish what you need to do, and it's very simple to use. You only need to call wait and notify_one:
void MyApp::main()
{
for(int i=0; i<total; ++i) {
pData->RegisterEvent( EVENT_LIBRARY_LOADED, this );
pData->OpenLibrary("c:/path/file.dat"); // asynchronous call
condition_variable.wait(); // wait until we've been signaled
}
}
void MyApp::OnEvent( ID eventType )
{
if (eventType == EVENT_LIBRARY_LOADED) {
qDebug() << "Library load has completed";
// signal completion:
condition_variable.notify_one();
}
}
Otherwise you could use Windows Event objects
These work very similar to the above but are a little more complicated to use (and also OS specific).
HANDLE hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
void MyApp::main()
{
for(int i=0; i<total; ++i) {
// Prepare signal (otherwise if the signal has been Set already, Wait will return instantly)
::ResetEvent(hEvent);
pData->RegisterEvent( EVENT_LIBRARY_LOADED, this );
pData->OpenLibrary("c:/path/file.dat"); // asynchronous call
// wait for event to signal:
::WaitForSingleObject(hEvent, INFINITE);
}
}
void MyApp::OnEvent( ID eventType )
{
if (eventType == EVENT_LIBRARY_LOADED) {
qDebug() << "Library load has completed";
// Signal event:
::SetEvent(hEvent);
}
}
Related
I want to implement a GUI that receives messages from an external device. The "advancedReceiveExample" is waiting for messages. Once it has received one, it does stuff with it, saves it and terminates.
I want to make my function wait for new messages after receiving one as long as the button is toggled.
I have tried this so far:
void MainWindow::on_pushButton_clicked()
{
if (ui.pushButton->isChecked()) {
ui.pushButton->setText("Stop Receiving");
ui.label_3->setText("Receiving...");
advancedReceiveExample(ui.comboBox->currentIndex() + 1);
}
else
{
ui.pushButton->setText("Start Receiving");
ui.label_3->setText("Not Receiving");
}
}
This works perfectly fine but as mentioned above it only receives one message. If I do that:
void MainWindow::on_pushButton_clicked()
{
if (ui.pushButton->isChecked()) {
ui.pushButton->setText("Stop Receiving");
ui.label_3->setText("Receiving...");
while (1)
{
advancedReceiveExample(ui.comboBox->currentIndex() + 1);
}
}
else
{
ui.pushButton->setText("Start Receiving");
ui.label_3->setText("Not Receiving");
}
}
it blocks the function because the state of the button can only be change after the function "on_pushButton_clicked()" has terminated.
Visual Studio 2019
C/C++
EDIT: Okay, I have understood the problem of blocking the thread. Multithreading might be the right option but I am very unexperienced regarding this topic. The <QThread> could be possible. How would you use it?
Do you have suggestions which other library could be used?
Note QT is event-based. If you keep your computer busy inside some function without returning to the main loop frequently, your GUI will freeze.
What you need to do is slice your action that you want to do into small bits that can repeatedly return to the main loop in order to keep the GUI responsive. (Another method yould be to swap out your action into a separate thread and handle it in parallel, killing the thread when the button is released)
Probably the simplest method to do what you want is with timers that you arm in the PushButton::clicked slot, and then check in the timer event whether the button is still pressed, and, if yes, do a bit of your action, save state and re-arm the timer to have you return.
Something along the lines of the following pseudo code should work and execute what you want to do in slices every 10ms:
MainWindow::onPushButtonClicked () {
// do the action, or, alternatively, start a
// parallel thread that does it
do_a_bit_of_action();
// sets up a timer to call onTimer after 10ms
QTimer::singleShot (10, this, SLOT(onTimer()));
}
MainWindow::onTimer () {
// check if button is still held down
if (pushButton.down) {
// re-arm timer
Timer::singleShot (10, this, SLOT(onTimer()));
// do some more action bits
do_a_bit_of_action();
}
else {
// kill optional background thread here
}
}
You can try it with:
while(ui.pushButton->isChecked()){
*your function*
}
I have a MFC GUI thread to send/read message to/from hardware and another MFC worker thread to send a few command over to control the hardware. How do I wait for a variable to be true before I continue to send the next command? the variable is set true when it receive an acknowledge message back from the hardware.
bool PortRead = false;
void onEventRead() // portread will be set to true from gui thread using callback to main thread
{
PortRead = true;
}
void sendCommands()
{
send (message1);
wait for Portread == true;
portread = false;
send (message2);
wait for Portread == true;
portread = false;
}
You can achieve this by either polling or an interruption (or callback).
if you want to poll, (also called busy waiting), something like this is enough:
// Send signal to hardware
while (!variable) {} // Waits here until variable is true
// Proceed with program
Interruptions are a little bit trickier, specially because you did not provide mode details about how you interface with that hardware, or if it has an API or library of some sorts. If you have control over the other thread, you could use std::condition_variable::wait, or even a signal/slot scheme using Qt and callbacks.
Based on your code, however, this may work:
std::condition_variable cv;
std::mutex cv_m;
void onEventRead()
{
cv.notify_all();
}
void sendCommands()
{
std::unique_lock<std::mutex> lk(cv_m);
send (message1);
cv.wait(lk);
send (message2);
cv.wait(lk);
}
For the full example of how to use std::condition_variable, see here: https://en.cppreference.com/w/cpp/thread/condition_variable/wait
Is there some way to make a function pause it's execution until the socket receives a specific message? Using Signals + QEventLoop to wait doesn't work because while it can wait for signals, there isn't any way to get the data the signal emitted (or is there?).
You could connect to the following signal:
void QIODevice::readyRead() [signal]
Then, you would basically read the data and if it is the one you are looking for, you could set a boolean variable to true that is initially false. Your function would continue the execution only when the variable is true.
Make sure that the function paused is not sleeping in a sync manner too much, etc, without having a dedicated thread.
So, this would be one way of solving your task:
MySocketManager::MySocketManager(QObject *parent): QObject(parent)
{
...
connect(m_mySocket, SIGNAL(readyRead()), SLOT(handleReadyRead()));
...
}
void MySocketManager::handleReadyRead()
{
if (m_mySocket.readAll() == "myMessage")
continue = true;
}
...
void myFunction()
{
...
continue = false;
qDebug() << "Pause";
while (!continue) { ... }
qDebug() << "Continue";
...
}
This is a tad simplication of the issue, but since you have not shown much effort other than asking for solution, this should get you started.
I've wrote a timer using std::thread - here is how it looks like:
TestbedTimer::TestbedTimer(char type, void* contextObject) :
Timer(type, contextObject) {
this->active = false;
}
TestbedTimer::~TestbedTimer(){
if (this->active) {
this->active = false;
if(this->timer->joinable()){
try {
this->timer->join();
} catch (const std::system_error& e) {
std::cout << "Caught system_error with code " << e.code() <<
" meaning " << e.what() << '\n';
}
}
if(timer != nullptr) {
delete timer;
}
}
}
void TestbedTimer::run(unsigned long timeoutInMicroSeconds){
this->active = true;
timer = new std::thread(&TestbedTimer::sleep, this, timeoutInMicroSeconds);
}
void TestbedTimer::sleep(unsigned long timeoutInMicroSeconds){
unsigned long interval = 500000;
if(timeoutInMicroSeconds < interval){
interval = timeoutInMicroSeconds;
}
while((timeoutInMicroSeconds > 0) && (active == true)){
if (active) {
timeoutInMicroSeconds -= interval;
/// set the sleep time
std::chrono::microseconds duration(interval);
/// set thread to sleep
std::this_thread::sleep_for(duration);
}
}
if (active) {
this->notifyAllListeners();
}
}
void TestbedTimer::interrupt(){
this->active = false;
}
I'm not really happy with that kind of implementation since I let the timer sleep for a short interval and check if the active flag has changed (but I don't know a better solution since you can't interrupt a sleep_for call). However, my program core dumps with the following message:
thread is joinable
Caught system_error with code generic:35 meaning Resource deadlock avoided
thread has rejoined main scope
terminate called without an active exception
Aborted (core dumped)
I've looked up this error and as seems that I have a thread which waits for another thread (the reason for the resource deadlock). However, I want to find out where exactly this happens. I'm using a C library (which uses pthreads) in my C++ code which provides among other features an option to run as a daemon and I'm afraid that this interfers with my std::thread code. What's the best way to debug this?
I've tried to use helgrind, but this hasn't helped very much (it doesn't find any error).
TIA
** EDIT: The code above is actually not exemplary code, but I code I've written for a routing daemon. The routing algorithm is a reactive meaning it starts a route discovery only if it has no routes to a desired destination and does not try to build up a routing table for every host in its network. Every time a route discovery is triggered a timer is started. If the timer expires the daemon is notified and the packet is dropped. Basically, it looks like that:
void Client::startNewRouteDiscovery(Packet* packet) {
AddressPtr destination = packet->getDestination();
...
startRouteDiscoveryTimer(packet);
...
}
void Client::startRouteDiscoveryTimer(const Packet* packet) {
RouteDiscoveryInfo* discoveryInfo = new RouteDiscoveryInfo(packet);
/// create a new timer of a certain type
Timer* timer = getNewTimer(TimerType::ROUTE_DISCOVERY_TIMER, discoveryInfo);
/// pass that class as callback object which is notified if the timer expires (class implements a interface for that)
timer->addTimeoutListener(this);
/// start the timer
timer->run(routeDiscoveryTimeoutInMilliSeconds * 1000);
AddressPtr destination = packet->getDestination();
runningRouteDiscoveries[destination] = timer;
}
If the timer has expired the following method is called.
void Client::timerHasExpired(Timer* responsibleTimer) {
char timerType = responsibleTimer->getType();
switch (timerType) {
...
case TimerType::ROUTE_DISCOVERY_TIMER:
handleExpiredRouteDiscoveryTimer(responsibleTimer);
return;
....
default:
// if this happens its a bug in our code
logError("Could not identify expired timer");
delete responsibleTimer;
}
}
I hope that helps to get a better understanding of what I'm doing. However, I did not to intend to bloat the question with that additional code.
I've a for loop that will launch processes in parallel every launched process will return a response back indicating that it is ready. I want to wait for the response and I'll abort if a certain timeout is reached.
Development environment is VS2008
Here is the pseudo code:
void executeCommands(std::vector<Command*> commands)
{
#pragma omp parallel for
for (int i = 0; i < commands.size(); i++)
{
Command* cmd = commands[i];
DWORD pid = ProcessLauncher::launchProcess(cmd->getWorkingDirectory(), cmd->getCommandToExcecute(), cmd->params);
//Should I wait for process to become ready?
if (cmd->getWaitStatusTimeout() > 0)
{
ProcessStatusManager::getInstance().addListener(*this);
//TODO: emit process launching signal
//BEGINNING OF QUESTION
//I don't how to do this part.
//I might use QT's QWaitCondition but if there is another solution in omp
//I'd like to use it
bool timedOut;
SOMEHANDLE handle = Openmp::waitWithTimeout(cmd->getWaitStatusTimeout(), &timedOut);
mWaitConditions[pid]) = handle;
//END OF QUESTION
if (timedOut)
{
ProcessStatusManager::getInstance().removeListener(*this);
//TODO: kill process
//TODO: emit fail signal
}
else
{
//TODO: emit process ready signal
}
}
else
{
//TODO: emit process ready signal
}
}
}
void onProcessReady(DWORD sourceProcessPid)
{
ProcessStatusManager::getInstance().removeListener(*this);
SOMEHANDLE handle = mWaitConditions[sourceProcessPid];
if (mWaitConditions[sourceProcessPid] != 0)
{
Openmp::wakeAll(handle);
}
}
As the comment above pointed out, Michael Suess did present a paper on adding this functionality to OpenMP. He is the last of several people that have proposed adding some type of wait function to OpenMP. The OpenMP language committee has taken the issue up several times. Each time it has been rejected because there are other ways to do this function already. I don't know Qt, but as long as the functions it provides are thread safe, then you should be able to use them.