|
-
March 17th, 2015, 01:00 PM
#16
Re: MFC: PostMessage and Handling it without the hassle (and a question).
 Originally Posted by VladimirF
This, unfortunately, will fail if you manage to post two or more messages before your window proc will get to process them.
Probably there are also other problems as long as we are trying to break the oldest but goodest "classic" way.
Still digging and having fun...
Last edited by ovidiucucu; March 17th, 2015 at 02:15 PM.
-
March 18th, 2015, 07:50 AM
#17
Re: MFC: PostMessage and Handling it without the hassle (and a question).
 Originally Posted by VladimirF
This, unfortunately, will fail if you manage to post two or more messages before your window proc will get to process them.
Correct, and the reason why this wouldn't have been possible in the particular case I needed this for.
the solution I posted in #1 doesn't have that issue, and applying the change codeplug suggested in #2 works as well and makes it even better. AND you can capture.
You do need to be careful about what you capture of course, since the message is posted, the processing of the lambda is asynchronous to where it's been declared, so the captured variables might already be gone by the time you get to execute the lambda body.
I also have a thing against any class member variables that only serve to make a class member function behave 'differently'.
-
March 18th, 2015, 03:10 PM
#18
Re: MFC: PostMessage and Handling it without the hassle (and a question).
 Originally Posted by OReubens
You do need to be careful about what you capture of course, since the message is posted, the processing of the lambda is asynchronous to where it's been declared, so the captured variables might already be gone by the time you get to execute the lambda body.
That's the reason why I made the capture by value. NO need to be a rocket scientist in order to know what happens with local variables when go out of scope. 
 Originally Posted by VladimirF
This, unfortunately, will fail if you manage to post two or more messages before your window proc will get to process them.
Please detail!
-
March 18th, 2015, 03:44 PM
#19
Re: MFC: PostMessage and Handling it without the hassle (and a question).
 Originally Posted by OReubens
I also have a thing against any class member variables that only serve to make a class member function behave 'differently'.
Absolutely agree.
However, the actual parameters can only (sic ) serve to make a class member function behave 'differently', as well.
-
March 18th, 2015, 04:06 PM
#20
Re: MFC: PostMessage and Handling it without the hassle (and a question).
 Originally Posted by ovidiucucu
Please detail!
Code:
void CMyDialog::OnFunButtonClicked()
{
PostedFunction( [](){ AfxMessageBox("Fun"); }
PostedFunction( [](){ AfxMessageBox("More fun"); }
}
with your suggestion, you'll have more fun twice and never have some normal fun.
-
March 18th, 2015, 04:52 PM
#21
Re: MFC: PostMessage and Handling it without the hassle (and a question).
 Originally Posted by OReubens
Code:
void CMyDialog::OnFunButtonClicked()
{
PostedFunction( [](){ AfxMessageBox("Fun"); }
PostedFunction( [](){ AfxMessageBox("More fun"); }
}
with your suggestion, you'll have more fun twice and never have some normal fun. 
Right, and I knew that. Although it's hard to believe that somebody can have the idea to write something like that (I discovered it just doing tests to find a solution), let's think like an "good architect" which believes that all developers are idiots.
And have more fun finding a KISS solution without writing wrappers everywhere, like all "good architects" do every time something is not exactly like they think to be. 
[ later edit ]
Just joking and having fun. No intention to offend the good architects...
Last edited by ovidiucucu; March 19th, 2015 at 05:37 AM.
-
March 19th, 2015, 07:58 AM
#22
Re: MFC: PostMessage and Handling it without the hassle (and a question).
The post was obviously the "smallest possible case where it fails" because we don't want all the irrelevant stuff in our forum posts when poiting out something.
In this particular case, I did have such cases where multiple posts were being done from a single message handler (though not right one after the other, they're all conditional, but multiple conditions cound be true).
so more something like
Code:
...
if (rgbColor==defcolor::yellow)
PostedFunction( []() { YellowificateEverything(); } );
...
if (vehicle==car)
PostedFunction( []() { Vroom(); } );
...
if ( GetNumPassengers()>1 )
PostedFunction( []() { OptimizePassengerSeatingArrangements(); } );
Now, it is possible the user was trying to make a yellow car with multiple passengers, so all 3 posts would be needed
P.S. The above code is an entirely ficticious example.
-
March 19th, 2015, 08:47 AM
#23
Re: MFC: PostMessage and Handling it without the hassle (and a question).
 Originally Posted by OReubens
[...]
so more something like
Code:
...
if (rgbColor==defcolor::yellow)
PostedFunction( []() { YellowificateEverything(); } );
...
if (vehicle==car)
PostedFunction( []() { Vroom(); } );
...
if ( GetNumPassengers()>1 )
PostedFunction( []() { OptimizePassengerSeatingArrangements(); } );
Now, it is possible the user was trying to make a yellow car with multiple passengers, so all 3 posts would be needed
P.S. The above code is an entirely ficticious example.
Sure.
But if someone is a good developer and not only a good architect ( ), has no sweat to put an '=' sign in lambda capture list, instead of shooting a burst in the message queue, from a single message handler.
Code:
// ...
// ...
// ...
theApp.PostLambda([=]() // capture all by value
{
if (rgbColor == defcolor::yellow)
YellowificateEverything();
if (vehicle == car)
Vroom();
if (GetNumPassengers() > 1)
OptimizePassengerSeatingArrangements();
});
-
March 19th, 2015, 11:41 AM
#24
Re: MFC: PostMessage and Handling it without the hassle (and a question).
To make possible multiple asynchronous lambda calls in the same message handler, one solution is to store them in a list.
These having been said, my example from post #14 can be improved a little bit as follows:
Code:
#include <functional>
#include <list>
// ...
class CSomeApplication : public CWinApp
{
static const UINT WM_APP_POST_LABDA = WM_APP + 1;
std::list<std::function<void()> > m_listLambdas;
// ...
public:
void PostLambda(std::function<void()> fn);
// ...
DECLARE_MESSAGE_MAP()
protected:
afx_msg void OnAppPostLambda(WPARAM wParam, LPARAM lParam);
// ...
};
Code:
// ...
ON_THREAD_MESSAGE(WM_APP_POST_LABDA, &CSomeApplication::OnAppPostLambda)
END_MESSAGE_MAP()
void CSomeApplication::OnAppPostLambda(WPARAM wParam, LPARAM lParam)
{
while (!m_listLambdas.empty())
{
if (m_listLambdas.front()) // if is callable,
{
m_listLambdas.front()(); // invoke,
}
m_listLambdas.pop_front(); // then remove it from list.
}
}
void CSomeApplication::PostLambda(std::function<void()> fn)
{
m_listLambdas.push_back(fn); // push lambda into the list
PostThreadMessage(WM_APP_POST_LABDA, 0, 0);
}
Code:
BOOL CSomeDialog::OnInitDialog()
{
CDialog::OnInitDialog();
// ...
theApp.PostLambda([=]() // capture all by value
{
// stuff...
});
theApp.PostLambda([=]() // capture all by value
{
// more stuff...
});
theApp.PostLambda([=]() // capture all by value
{
// much more stuff...
});
// and so on...
return TRUE;
}
For sure, still there are other solutions.
Digging is fun!
Last edited by ovidiucucu; March 19th, 2015 at 11:45 AM.
-
March 19th, 2015, 12:06 PM
#25
Re: MFC: PostMessage and Handling it without the hassle (and a question).
note that neither this nor your previous example are thread safe, if PostLambda is invoked by different threads. BTW, what's wrong with the unique_ptr<> approach ? if your aim is to avoid the free store allocation, note that std::function will allocate its storage on the heap anyway ( unless the lambda is very small, like a mere this pointer for example ).
-
March 20th, 2015, 04:14 AM
#26
Re: MFC: PostMessage and Handling it without the hassle (and a question).
Indeed, the solution from previous example is not thread safe.
So, to prevent calling CSomeApplication::PostLambda from a thread, other than main application's thread, we can simply use an ASSERT.
Code:
void CSomeApplication::PostLambda::PostLambda(std::function<void()> fn)
{
ASSERT(::GetCurrentThreadId() == m_nThreadID); // don't call me from other thread, dude!
m_listLambdas.push_back(fn); // add lambda to the list
PostThreadMessage(WM_APP_POST_LABDA, 0, 0);
}
or, if really want to call it from multiple threads, it's no sweat to synchronize the list operations.
Code:
class CSomeApplication : public CWinApp
{
CCriticalSection m_cs;
// ...
Code:
void CSomeApplication::OnAppPostLambda(WPARAM wParam, LPARAM lParam)
{
m_cs.Lock();
while (!m_listLambdas.empty())
{
if (m_listLambdas.front()) // if it's callable,
{
m_listLambdas.front()(); // invoke,
}
m_listLambdas.pop_front(); // and finally, remove it from list.
}
m_cs.Unlock();
}
void CSomeApplication::PostLambda(std::function<void()> fn)
{
m_cs.Lock();
m_listLambdas.push_back(fn); // add lambda to the list
m_cs.Unlock();
PostThreadMessage(WM_APP_POST_LABDA, 0, 0);
}
Personally, I would like to use the first solution.
About storing the functions in the list.
There is an old issue, still present, about MFC macro ON_THREAD_MESSAGE: https://support.microsoft.com/en-us/kb/142415.
Using the list gets rid of this problem.
-
March 20th, 2015, 07:47 AM
#27
Re: MFC: PostMessage and Handling it without the hassle (and a question).
 Originally Posted by ovidiucucu
Sure.
But if someone is a good developer and not only a good architect (  ), has no sweat to put an '=' sign in lambda capture list, instead of shooting a burst in the message queue, from a single message handler.
Code:
// ...
// ...
// ...
theApp.PostLambda([=]() // capture all by value
{
if (rgbColor == defcolor::yellow)
YellowificateEverything();
if (vehicle == car)
Vroom();
if (GetNumPassengers() > 1)
OptimizePassengerSeatingArrangements();
});
AGain, too elaborate to give the full explanation, but this wouldn't have worked in this case, they did needed to be independantly posted messages. Besides now you're assuming the handler has easy access to all those things that in this approach need to be captured. The above could be a much heavier approach because you're capturing a lot more.
-
March 20th, 2015, 07:50 AM
#28
Re: MFC: PostMessage and Handling it without the hassle (and a question).
 Originally Posted by ovidiucucu
To make possible multiple asynchronous lambda calls in the same message handler, one solution is to store them in a list.
true but.
1) you're still having member variables in the class that serve no other purpose than to make a called (posted) function behave differently.
2) This is a much more elaborate and less elegant solution than just posting the (new-ed lambda).
3) you might now have to deal with synchronisation if the list needs to be accessible from multiple threads.
-
March 20th, 2015, 07:57 AM
#29
Re: MFC: PostMessage and Handling it without the hassle (and a question).
 Originally Posted by ovidiucucu
Code:
void CSomeApplication::OnAppPostLambda(WPARAM wParam, LPARAM lParam)
{
m_cs.Lock();
while (!m_listLambdas.empty())
{
if (m_listLambdas.front()) // if it's callable,
{
m_listLambdas.front()(); // invoke,
}
m_listLambdas.pop_front(); // and finally, remove it from list.
}
m_cs.Unlock();
}
Well, you would really want to NOT put the invoke of the lamba inside the CS lock.
For one it might cause a deadlock (and it certainly will if the lambda again posts more lambdas) but even without that case, there might be issues.
You're also locking a CS for much longer than you really need to, so even if this DOES work, you're blocking your other threads for longer than necessary which lowers throughput, which is one of the reasons to go multithreaded in the first place.
I said it before on CG, the basics of MT is easy. But it's hard to do right ;-)
Personally, I would like to use the first solution.
;-)
hence why it thought it was an interesting approach that I wanted to share with you all...
If you can use it, then by all means do so. If you don't see the point of this, nobody is forcing you to use it
-
March 20th, 2015, 09:47 AM
#30
Re: MFC: PostMessage and Handling it without the hassle (and a question).
Another reason why I said "I would like to use the first solution" is to avoid shuffling lambda calls in worker threads. I'm not sure if that matters but who knows... anytime a mighty architect may appear, finding a reason to complain. 
Anyway, still I think "it's better to follow the classic MFC way". Or better said, more headache-less.
The rest is just the fun of digging...
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|