I am trying to debug a C++ MFC windows service application as we have found that in high-intensity environment there becomes a lag between the receipt and processing of third-party messages.
The service listens for received messages from a third-party system. On receiving a message, it passed the message to a dedicated processing thread which does all the processing of the command. The problem, as aforementioned, is that we are seeing a significant lag in the receipt and processing. We can see this because all messages include a sequence number. For example, our tracing reports that the main thread receives a message with sequence number 867 at 13:00:00, but we do not see the corresponding trace from the processing thread until 13:00:38 (this is a real-time system, so ideally it would be instantaneous).
I can also see in the tracing that, where on a normal system we would see a clean sequence of Receipt-Process-Receipt-Process-Recepit-Process etc..... on this log we have a block of 4 or 5 receipt messages, followed by 4 or 5 process messages, then another 4 or 5 receipt messages, and so on. Since these are running on different threads this surprises me, as I would expect to see the traces interspersed, even if delayed.
In the code, there is a message map like so:
BEGIN_MESSAGE_MAP(CProcessorThread, CWinThread)
ON_THREAD_MESSAGE(WM_MSG_RCV, OnReceive)
END_MESSAGE_MAP()
The thread class looks like this (slightly abridged):
class CProcessorThread : public CWinThread {
protected:
DECLARE_MESSAGE_MAP()
private:
CAMProcessingObject *obj;
afx_msg void OnReceive(WPARAM wParam, LPARAM lParam) {
CString* strRecData = (CString*)wParam;
CString& sTemp = *strRecData;
// Various checks and filters are done here
if (true) {
obj->ProcessMessage(sTemp);
}
delete strRecData;
}
}
Here is the method that initially receives the message from the third-party system (again, abridged):
DWORD WINAPI CAMReceiving::ThreadReceive( void * args) {
CAMObject * camObject = (CAMObject *) args;
char chTemp[500];
while(true) {
// Get the message from the socket
memset(chTemp, 0, sizeof(chTemp));
iRecvLen = camObject->objsocket.ReceiveData(chTemp, sizeof(chTemp) - 1);
CString strEventNotification = _T("");
// Do various processing to populate the strEventNotification CString and make sure we want to process this message
CString* strEvent = new CString(strEventNotification);
processorThread.PostThreadMessageA(WM_MSG_RCV,(WPARAM)strEvent,0);
continue;
}
return 1;
}
So as you may tell I didn't write this and I'm not particular familiar with the multithreading methods in C++, so my question is really is there something fundamentally wrong with this design? Or is there something I don't know that is going to cause me problems here? Thanks in advance!
Related
I am new to C ++ and I am designing an application that requires getting information from the internet, my problem is that if there is no internet connection, or this is slow, my application freezes for seconds. My application also has a hook to the keyboard so when my application freezes, Windows also does.
My application is for Windows only.
This is a simulation of my problem:
std::string instruction;
std::string otherValue;
int timerId;
int main(int argc, char* argv[])
{
StartKeysListener(); //Keyboard Hook
timerId = SetTimer(nullptr, 0, 5000, static_cast<TIMERPROC>(TimerCallback));
MSG msg;
while (GetMessageA(&msg, nullptr, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
VOID CALLBACK TimerCallback(HWND hwnd, UINT message, UINT idTimer, DWORD dwTime)
{
DownloadInstructions();
}
std::string DownloadInstructions(std::string url)
{
std::string response = HttpRequest(url); //HttpRequest is a function that uses Windows SOCKET to send an http request
if (!response.empty())
{
instruction = response.substr(0, 5);
otherValue = response.substr(6, 15);
}
}
I have tried calling the "DownloadInstructions" function on a new thread using std::async but I do not know how to return the server response to a callback to update the "instruction" and "otherValue" variables.
How can i solve this problem? I could not find what I'm looking for on Google.
Given you are using a Win32 style message loop, the usual way to pass information back to the main thread from a worker thread is to send a message. (It doesn't look like your sample code would quite work as written as you need at least a dummy HWND though.)
Custom messages (as opposed to predefined system messages) can be defined as an offset from WM_APP, so you can do something like:
#define WM_INSTRUCTIONS_LOADING (WM_APP + 0)
#define WM_INSTRUCTIONS_READY (WM_APP + 1)
/* ... */
Then in DownloadInstructions you can notify the main thread that the download is complete by using the PostMessage API (which sends an asynchronous message) where the HWND parameter is passed in to the thread from your main loop:
PostMessage(WM_INSTRUCTIONS_READY, hwndMain, 0, 0);
Now it doesn't look like DownloadInstructions is actually running in another thread. You're using the SetTimer API which will just send a WM_TIMER message to your event loop at some point in the future. The message will still be processed in your event loop, and thus on the main thread.
You really do need to spawn a separate thread if you want it to be truly asynchronous. The mechanism for using std::async and is quite different to using CreateThread. The std::async call will spawn a thread and return you a std::future which you need to join on to get the result. This is probably not a great match for your current design. If you just spawn DownloadInstructions as a separate thread and pass it some context (at least the HWND to post back to) via the void* argument pointer, that should be sufficient to do what you describe.
Now having said all that, are you sure you want to write a C++ app using the rather old-fashioned and low-level C Win32 API? There are numerous libraries and frameworks for C++ which provide a much higher level API to do all these sorts of things more easily.
am new in C++ GUI, am modifying a code sent with a machine to me, i want to make a while loop when i click button, i tried the thread and it is still stuck.
void CDlgWriteEPC::loop()
{
// Do something
}
void CDlgWriteEPC::OnBnClickedOk()
{
std::thread loadingThread(&CDlgWriteEPC::loop, this);
loadingThread.join();
}
join blocks the current thread until the other thread is done, so that's no help.
You should start the worker thread, return immediately and the worker thread
should send some kind of message when it's done.
The function names in your example code seem to look like it's from a MSVC++ MFC
application so we'll work with that.
Simply put, windows GUI applications are event driven, each time a event happens a
WM_MESSAGE is sent. The framework receives these messages and calls the appropriate
functions to handle it. We can define our own messages and message handlers.
This way the worker thread can send such messages to the framework and it will call
our handler function.
WM_APP is defined as a starting point for private user messages, so there won't be
any conflict with already existing system messages.
(https://msdn.microsoft.com/en-us/library/windows/desktop/ms644930%28v=vs.85%29.aspx)
So, imagine we are building a MFC dialog application that searches something in a file.
If the file is big it can take a long time and to prevent blocking the main thread and
getting a 'window is not responding' message we need to do this in a worker thread. We might
also want a progress bar for example.
First, we define our own messages inside our existing dialog class starting from WM_APP + 1
and we add our handler functions, these must be of the following type:
afx_msg LRESULT (CWnd::*)(WPARAM, LPARAM)
WPARAM and LPARAM are parameters passed when posting the message, you can use them to send
custom data. In our example we can use them to send the % progress for our progress bar.
(https://msdn.microsoft.com/en-us/library/k35k2bfs.aspx)
class CMyAppDlg : public CDialogEx
{
public:
//Public so the worker thread class can use these same sames when posting a message.
enum Messages
{
MSG_ThreadProgress = WM_APP + 1,
MSG_ThreadDone
};
private:
afx_msg LRESULT OnThreadProgress(WPARAM wParam, LPARAM lParam)
{
ProgressBar->SetPos(wParam); //Worker thread posts progress as wParam
};
afx_msg LRESULT OnThreadDone(WPARAM wParam, LPARAM lParam)
{
//Get result from worker thread class and use it...
};
};
Then we need to add our messages and handlers to the message map, you should add them to the already
existing message map in the .cpp file for the dialog/document.
BEGIN_MESSAGE_MAP(CMyAppDlg, CDialogEx)
ON_MESSAGE(MSG_ThreadProgress, &CMyAppDlg::OnThreadProgress)
ON_MESSAGE(MSG_ThreadDone, &CMyAppDlg::OnThreadDone)
END_MESSAGE_MAP()
Now we can simply post these messages in our worker thread and the framework main thread will handle
the messages and update the progress bar or use the result:
class ThreadClass
{
public:
//Constructor takes a reference to our dialog class because we need the window handle
//to post a message
ThreadClass(CMyAppDlg& MyAppDlg) : mMyAppDlg(MyAppDlg) {};
void operator()() //Thread worker code...
{
while (what_we_look_for_not_found)
{
int Progress = 0;
//Search for a while and update progress variable...
//Post message to dialog asking it to update the progressbar
PostMessage(mMyAppDlg.m_hWnd, CMyAppDlg::MSG_ThreadProgress, Progress, 0);
}
//Finished searching...
StoreResult();
//Post message to dialog informing it thread is done and result can be retrieved.
PostMessage(mMyAppDlg.m_hWnd, CMyAppDlg::MSG_ThreadDone, 0, 0);
}
private:
CMyAppDlg& mMyAppDlg;
};
QT uses a similar system with SIGNAL and SLOT and other frameworks surely have their own equivalent system.
You should be able to find more information in the manuals if you are using something else then MSVC++ MFC.
I've written a simple console application using windows sockets to work as a proxy between a server and a client. I decided to make a graphical interface for watching all the in/outgoing packets real time (like a very simple wireshark).
The connection between the server and the client runs on a different thread than the message loop. When the server/client sends a packet, I would like that to be displayed (for example added to a simple text control) immediately.
But since I can not access the forms from other thread than the thread where the message loop is I dont know how to handle this.
I've found several solutions in:
- Managed c++
- C++/CLI
- C#,
but not any without using .NET platform. (I really new to this GUI topic so I am not even sure you can use windows forms without .NET)
Maybe QT + C++ could handle this problem, but any other solution than that? If not is it possible to write a wrapper in C# / Java for the native C++ code?
There must be many applications written in C/C++ which using a GUI, what is the general way to do that?
You are absolutely correct that you cannot access a window in a different thread. The proper way to handle this to post a message using the ::PostMessage Win32 API command (or, if you are using a wrapper library around Win32, whatever function in that wrapper that eventually calls PostMessage). Here's a useful link from Microsoft regarding message queues:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644928(v=vs.85).aspx
There is an alternative one, free and open-source, called Nana C++ Library (http://stdex.sourceforge.net), a pure C++ GUI library.
By using Nana library, the multithreading issue can be fixed easily. There is an article on the multithreading in GUI, it would be a choice for your hobby project.
A quick and dirty Win32 solution would involve a critical section, a text buffer, and a timer in the UI thread.
Define a few globals...
CRITICAL_SECTION bufferLock; // critical section (to be initialized somewhere)
char dataBuffer[65536]; // contains the data that will be sent to the form
int newdata = 0; // how much data we got (this variable must be atomic, int is ok)
char uiDataBuffer[65536]; // data available to the form
int overflow = 0; // just in case...
UI thread timer
void onTimer ()
{
if (overflow)
{
// handle this
}
else
if (newdata) // new data to display
{
// take the lock, copy the data and release the lock quickly
EnterCriticalSection(&bufferLock);
int dataread = newdata;
memcpy(uiDataBuffer, dataBuffer, dataread);
newdata = 0;
LeaveCriticalSection(&bufferLock);
// TODO: append the text in uiDataBuffer[] to your text control
}
}
To be called from the worker thread:
void sendData (char* data, int size)
{
EnterCriticalSection (&bufferLock);
if(size+newdata > 65536)
overflow = 1;
else
{
memcpy(dataBuffer+newdata, data, size);
newdata += size;
}
LeaveCriticalSection (&bufferLock);
}
Code untested. Buffer size and timer frequency are to be adjusted.
It is possible to avoid polling the buffer with the timer by using PostMessage() (with a custom message) to signal the UI that new data is available.
If performance is an issue, data exchange between a producer and a consumer thread can also be performed very efficiently with a lock-free FIFO queue.
PostMessage() alone is not a solution to exchange data between threads.
I tried to create a dialog in a UI thread(CWinThread).
However, it crashes when the CDialog::Create() is called.
I had verified with previous implementation, the dialog is successfully created in non-threading mode.
Does any guru here know the crash reason of creating a dialog in CWinThread?
Without Threading:
class CProduction : public CDialog{
...
}
class CScrollProductionView : public CScrollView{
CProduction *m_pProduction;
...
}
void CScrollProductionView::OnInitialUpdate(){
m_pProduction = new CProduction(0, *m_pVisionAdapter);
m_pProduction->Create(IDD_DLG_PROD, this); //--> created dialog successfully
m_pProduction->ShowWindow(SW_SHOW);
}
Implement UI Thread:
class CProduction : public CDialog{
...
}
class CScrollProductionView : public CScrollView{
CProductionThread* m_pProdThread;
...
}
class CProductionThread : public CWinThread{
CProduction *m_pProduction;
...
}
void CScrollProductionView::OnInitialUpdate(){
m_pProdThread->PostThreadMessage(WM_INITPRODTHREADMESSAGE, PROD_INIT, (LPARAM)m_pVisionAdapter);
m_pProdThread->PostThreadMessage(WM_INITPRODTHREADMESSAGE, PROD_CREATE_DLG, (LPARAM)this);
}
void CProductionThread::InitMessageHandler(WPARAM wParam, LPARAM lParam)
{
printf("Receiving InitMessageHandler msg %d\n", (UINT)wParam);
switch(wParam)
{
case PROD_INIT:
{
CVisionAdapter* pAdapter = (CVisionAdapter*)lParam;
m_pProduction = new CProduction(NULL, *pAdapter);
}
break;
case PROD_CREATE_DLG:
{
CScrollProductionView* pView = (CScrollProductionView*)lParam;
m_pProduction->Create(IDD_DLG_PROD, pView); //--> Crash here
m_pProduction->ShowWindow(SW_SHOW);
}
break;
default:
break;
}
}
Error message:
Debug Assertion Failed! ..
File: .... wincore.cpp
Line: 9906
Thanks you for viewing this question.
Try not to create CWinThread, instead of creating a worker thread, if you have many communication between classes like passing object pointers, strings etc.
You will feel less headache if update the GUI through message handling.
I suspect that the problem is that your CProduction object has not been created when the PROD_CREATE_DLG message is being handled. This may be because of using PostThreadMessage. Using PostThreadMessage is fraught with problems. In particular, the messages may get lost, so the thread never sees the PROD_INIT message.
In the single-threaded code you create your CProduction object right before the Create call. Why don't you do the same in the multi-threaded code?
If you really want to use windows messages to communicate between your threads, I would create a "message only" window (See http://msdn.microsoft.com/en-us/library/ms632599.aspx#message_only) instead, as the window messages will not get lost in the same way that the thread messages do.
Alternatively, use a thread-safe queue to pass custom messages between threads, such as my example queue at http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html
The crash is caused by MFC referring invalid window handle (which passed in as parent) during creation.
As a general rule, a thread can access
only MFC objects that it created. This
is because temporary and permanent
Windows handle maps are kept in thread
local storage to help maintain
protection from simultaneous access
from multiple threads.
http://msdn.microsoft.com/en-us/library/h14y172e(VS.71).aspx
an easy fix stated in the MSDN involves changing the code into
...
m_pProdThread->PostThreadMessage(WM_INITPRODTHREADMESSAGE, PROD_CREATE_DLG, (LPARAM)this->GetSafeHwnd());
...
CScrollProductionView* pView = (CScrollProductionView*)CScrollProductionView::FromHandle((HWND)lParam);
m_pProduction->Create(IDD_DLG_PROD, pView);
m_pProduction->ShowWindow(SW_SHOW);
Edit:
Fixed the link to msdn.
My application (the bootstrap application for an installer that I'm working on needs to launch some other applications (my installer and third party installers for my installer's prerequisites) and wait for them to complete. In order to allow the GUI to do screen updates while waiting for an app to complete, I put a message pump in the wait loop using the 'MFC-compatible' example in the Visual Studio documentation on idle loop processing as a guideline. My code (which is in a member function of a CWinApp-derived class) is as follows:
if (::CreateProcess(lpAppName, szCmdLineBuffer, NULL, NULL, TRUE, 0, NULL, NULL,
&StartupInfo, &ProcessInfo))
{
::GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
if (bWait)
while (dwExitCode == STILL_ACTIVE)
{
// In order to allow updates of the GUI to happen while we're waiting for
// the application to finish, we must run a mini message pump here to
// allow messages to go through and get processed. This message pump
// performs much like MFC's main message pump found in CWinThread::Run().
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!PumpMessage())
{
// a termination message (e.g. WM_DESTROY)
// was processed, so we need to stop waiting
dwExitCode = ERROR_CANT_WAIT;
::PostQuitMessage(0);
break;
}
}
// let MFC do its idle processing
LONG nIdle = 0;
while (OnIdle(nIdle++))
;
if (dwExitCode == STILL_ACTIVE) // was a termination message processed?
{
// no; wait for .1 second to see if the application is finished
::WaitForSingleObject(ProcessInfo.hProcess, 100);
::GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
}
}
::CloseHandle(ProcessInfo.hProcess);
::CloseHandle(ProcessInfo.hThread);
}
else
dwExitCode = ::GetLastError();
The problem that I'm having is that, at some point, this message pump seems to free up window and menu handles on the window that I have open at the time this code is run. I did a walk through in the debugger, and at no time did it ever get into the body of the if (!PumpMessage()) statement, so I don't know what's going on here to cause the window and menu handles to go south. If I don't have the message pump, everything works fine, except that the GUI can't update itself while the wait loop is running.
Does anyone have any ideas as to how to make this work? Alternatively, I'd like to launch a worker thread to launch the second app if bWait is TRUE, but I've never done anything with threads before, so I'll need some advice on how to do it without introducing synchronization issues, etc. (Code examples would be greatly appreciated in either case.)
I've also posted this question on the Microsoft forums, and thanks to the help of one Doug Harris at Microsoft, I found out my problem with my HWND and HMENU values was, indeed due to stale CWwnd* and CMenu* pointers (obtained using GetMenu() and GetDialogItem() calls. Getting the pointers again after launching the second app solved that problem. Also, he pointed me to a web site* that showed a better way of doing my loop using MsgWaitForMultipleObjects() to control it that doesn't involve the busy work of waiting a set amount of time and polling the process for an exit code.
My loop now looks like this:
if (bWait)
{
// In order to allow updates of the GUI to happen while we're
// waiting for the application to finish, we must run a message
// pump here to allow messages to go through and get processed.
LONG nIdleCount = 0;
for (;;)
{
MSG msg;
if (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
PumpMessage();
else //if (!OnIdle(nIdleCount++))
{
nIdleCount = 0;
if (!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
DWORD nRes = ::MsgWaitForMultipleObjects(1, &ProcessInfo.hProcess,
FALSE, INFINITE, QS_ALLEVENTS);
if (nRes == WAIT_OBJECT_0)
break;
}
}
}
}
::GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
*That Web site, if you're curious, is: http://members.cox.net/doug_web/threads.htm
I think your problem is in WaitForSingleObject
Looking in MSDN you see this
Use caution when calling the wait functions and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. A thread that uses a wait function with no time-out interval may cause the system to become deadlocked. Two examples of code that indirectly creates windows are DDE and the CoInitialize function. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than WaitForSingleObject.
In my code in the message pump use use MsgWaitForMultipleObjects (doc).
With a call this call.
MsgWaitForMultipleObjects(1, &ProcessInfo.hProcess, FALSE, 100, QS_ALLEVENTS);
This should stop your problem with the resources dissapearing.
When you say that window and menu handles seem to be being freed, do you mean that you've got actual HWND and HMENU values that no longer seem to work, or have you got MFC CWnd* and CMenu* variables that fail?
If the latter, the problem is most likely that you're getting the CWnd* pointers by calling CWnd::FromHandle() (or CMenu::FromHandle()) somewhere (or calling something that calls them), and OnIdle() is discarding them.
The underlying reason is that MFC maintains a map from window (or menu, etc.) handles to CWnd* objects in the system. When CWnd::FromHandle() is called, it looks for a match in the map: if one is found, it's returned. If not, a new, temporary CWnd is created, added to the map, and returned. The idea behind OnIdle() is that when it's called all message processing is done, so OnIdle() discards any of these temporary CWnd objects that still exist. That's why the CWnd::FromHandle() documentation warns that the returned pointer may be temporary.
The "correct" solution to this is to not hang onto the CWnd* pointers returned from CWnd::FromHandle(). Given the simplicity of your application, it might be easier to just remove the call OnIdle(): this shouldn't have any negative effects on an installer.
Of course, this is all something of a guess, but it sounds plausible...
There is a Windows function called DisableProcessWindowsGhosting (see http://msdn.microsoft.com/en-us/library/ms648415(v=vs.85).aspx) that prevents Windows from 'ghosting' your window, and continue updating the window (your animation).