1

Here is my context. MyApp exits normally by clicking on either the OK or the Cancel dialog button. MyApp also maintains a TCP connection to another app, HerApp. Before MyApp can normally exit by clicking on one of these buttons, it needs to inform HerApp that it is going offline. This advisory message is sent to HerApp via a socket defined using this derived class: class TxSocket : public CAsyncSocket. HerApps TCP listener replies which comes in on MyAppss TxSocket::OnReceive.

My problem is MyApp ends before the TCP OnReceive occurs.

I have thought of several approaches. Obviously, I cannot block the Main thread while the socket interaction completes because it too is running on the Main thread. I can’t let the Main thread go out of scope either because normal app exit in C++ means all its resources are cleaned up including resources used in any other threads (see cppreference Main function: “… destroys the objects with automatic storage duration…” ), so just launching another thread, which has automatic storage, merely to send the advisory message and wait for a receipt, is out of the question too. Statics are destroyed too so no help there. As a result, these techniques can’t be used either: use of std::thread in conjunction with std::packaged_task, the use of std::async or the setting and retrieving of std::promises and std::futures because the get_future object’s get() would block the Main thread too. I could create an intermediary thread that creates these flag objects, but again, they would all get prematurely destroyed on MyApps exit. The [What happens to a detached thread when main() exits?] (What happens to a detached thread when main() exits?) posting explores what happens when you detach a thread, but I found the answers to be non-definitive, at least for me as an app developer.

I need help finding a good and simple C++ approach to solving this synchronization problem which, I predict, will be quite common once we get past the Web HTML era.

Edit 1: In order to clarify the context of my problem, here my MFC on cancel handler:

void MyAppDlg::OnCancel()
{
  myApp->UseTcpioEngineToSendHerAppAdvisoryMsgThatMyAppHasCanceledExpectConfirmationReply(); // fails because connection and io objects get destroyed before completion

  CDialog::OnCancel();
} // all automatic static etc storage is destroyed and exit is called
Community
  • 1
  • 1
rtischer8277
  • 496
  • 6
  • 27
  • 1
    Why do you need to wait for a response from an **advisory** message anyway? It's a fire and forget kind of thing. It's not like you would check if destructors run in C++ either. Sometimes there's just no conceivable way to handle failure, and this is one of them. – IInspectable Sep 21 '16 at 16:19
  • boost::asio will be a good starting point for this – seccpur Sep 21 '16 at 16:44
  • @seccpur boost::asio seems to be an alternative to the CAsyncSocket IO approach I have taken. No need to switch systems since the current tcp io is already fully implemented and tested in my app. – rtischer8277 Sep 21 '16 at 18:26
  • @IInspectable sending a reply to the sender is part of the design of my system so it doesn't matter whether the value of the message is advisory or, say, the transmission of encrypted data. – rtischer8277 Sep 21 '16 at 18:26
  • Sounds like a broken design then. It's almost like saying that you are using `std::list` everywhere, because you get O(1) insertion everywhere (even when you don't need it). And you now need a way to pass that `std::list` to an API that expects a contiguous array. – IInspectable Sep 21 '16 at 18:35
  • 2
    @IInspectable your job w/r/t this question is not to shoot at my io design. That is irrelevant. Please try to find something substantive to say about the question as posed. – rtischer8277 Sep 21 '16 at 19:29
  • This is tagged "mfc", but I'm having a hard time grasping your App's structure in this context from your description. For a normal Dialog App, MFC doesn't expose a `main` function, rather you override `CWinappEx::InitInstance` and there is a call to your dialog class' `DoModal` function. Maybe you have a console app which somehow uses MFC to pop up a dialog? I don't know. There should be a place after the window closes, but before termination where you could block to wait for a response, but without a clear description we can only provide vague guesses at a solution. – Christopher Oicles Sep 21 '16 at 23:55
  • @ChristopherOicles: Any MFC application will abstract the message loop implementation away. You won't have a say in this. Implementing this requirement using a custom message loop based on [MsgWaitForMultipleObjects](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684242.aspx) would be a walk in the park. With MFC you'll have to implement a kludge, one way or another. Anyway, it's probably not my job to explain these useless details, according to the OP. – IInspectable Sep 22 '16 at 09:19
  • @IInspectable You misrepresent MFC. MFC does a service in abstracting the message loop away which is convenient in most cases. Since MFC is written in native C++ which lately has been upgraded with C++11, C++14 and even some of C++17, you have access to any and all global and system functions, C and even Assembler if needed which of course includes `MsgWaitForMultipleObjects`. – rtischer8277 Sep 22 '16 at 13:11
  • @IInspectable I can see your point that if you had direct control of the message loop, you could easily wait for all multiple objects, one event being `OnCancel` and the other `TxSocket::OnReceive`. Is that your point? Wouldn’t the loop block until both events had fired? – rtischer8277 Sep 22 '16 at 13:38
  • @ChristopherOicles My real app is written in MFC, but my problem description only abstracts the problem in terms of the Main function. I should have included either MFC `OK` or `Cancel` handler code. I have added an **Edit 1** note to clarify. – rtischer8277 Sep 22 '16 at 13:44
  • *"Wouldn’t the loop block until both events had fired?"* - As [documented](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684242.aspx), you have full control over that: *"bWaitAll: If this parameter is TRUE, the function returns when the states of all objects in the pHandles array have been set to signaled and an input event has been received. If this parameter is FALSE, the function returns when the state of any one of the objects is set to signaled or an input event has been received."* – IInspectable Sep 22 '16 at 13:56
  • *"You misrepresent MFC. [blah blah] you have access to any and all global and system functions, C and even Assembler if needed which of course includes MsgWaitForMultipleObjects."* - That's not going to help you undo the structure, that's set in stone (compiled to object code). You **can** call `MsgWaitForMultipleObjects` (or any other Windows API). You **cannot** call it in the right place, though. If you find that this is misrepresenting the **fixed** structure of an MFC application, feel free to solve your pressing issue, so that you get to keep your broken IO design. – IInspectable Sep 22 '16 at 13:59
  • As an aside: MFC is pre-98 (i.e. pre-standard) C++, really. Nothing has changed in that department. You still have to manually delete MFC exceptions that you happen to catch. – IInspectable Sep 22 '16 at 14:01
  • Ok, don't call the default `OnCancel` from your `OnCancel` handler (this is actually what is ending your app), then when your `CAsyncSocket` handler verifies a response from Her, it can initiate the dialog's destruction. The simplest way would be to call your dialog's `EndDialog(IDCANCEL)`. But a cleaner way would be to add a custom message to your dialog which cleans up anything and calls `EndDialog` or CDIalog::OnCancel. Also, you should probably use a timer to implement a timeout in case the response from Her is not received. – Christopher Oicles Sep 22 '16 at 17:45
  • @IInspectable MFC is a rather concise and fast C++ interface to the Windows OS (see “Programming Windows with MFC” by Jeff Prosise). Available ISO C++ standard programming idioms has been constantly updated since 1998. In fact, as the C++ standard matures, the percentage of my app’s code that is Windows-specific C++ MFC is less and less. There is no danger of the programming power of C++ MFC becoming obsolete except one: if Microsoft were to abandon Windows, at which point I and millions of other C++ MFC app owners, would move to another OS or microkernel taking our standard code with us. – rtischer8277 Sep 23 '16 at 13:24
  • @Christopher Oicles *when your CAsyncSocket handler verifies a response from Her, it can initiate the dialog's destruction* Please elevate your response to answer. Not sure I need to handle the OnCancel as a user-defined message though. Rather just remove the terminating `CDialog::OnCancel`. Key however is your observation that real handling has to occur when the Her response has arrived and not before. I will add a timer. I will also make a note in the posting as to how it turns out for my case. – rtischer8277 Sep 23 '16 at 13:47
  • I don't really have the time to make this an answer, and really you did all the work, so I would fully support and upvote a self-answer from you which goes over what you needed to do to get your app working. (Leave out any of my suggestions which weren't helpful or applicable -- like you probably didn't need to use custom messages). – Christopher Oicles Sep 23 '16 at 20:39
  • Oh and by the way, it sounds like your I/O design is the standard way MFC does I/O, so there's nothing broken about it, excepting that MFC itself might be considered "broken." MFC has a ton of overridable handlers and member functions, I've always been able to find a callback located where I wanted to add my own code (albeit a bit of research was needed to find out about some of the less commonly used ones). MFC is probably on a slow road to deprecation, but there are few alternatives which offer its convenience and control on a low level. WTL, maybe, but it lacks support. – Christopher Oicles Sep 23 '16 at 21:17

0 Answers0