Implementing progress control using threading - c

I am new to the concept of threading in C, so I find it difficult to implement that
in my function. I have a simple application in which I want to display a progress bar at a
particular place. In a particular function I will read files(in a for loop) for some manipulations(regarding my application). While it's reading the files I want to display a progress bar, stating that it's in process of reading files. I know it should be done using the concept of threading, but I am not quite sure how to do it.

Create a worker thread in the main program and set the callback routine that does the file processing.
That routine also will calculate the percentage that is completed. Whenever that percent changes, post the
value as a window message which the main thread will catch and update the progress bar control.
You can define application inner messages like #define MSG_PROGRESS_VALUE (WM_USER + 1).
Edit: sample,
#define MSG_PROGRESS_VALUE (WM_USER + 1)
#define MSG_WORKER_DONE (WM_USER + 2)
...
DWORD WINAPI jobroutine(LPVOID lpParameter) {
while (TRUE) {
// process files ...
// calculate new percent
if (newpercent != oldpercent) {
PostMessage(mainwnd, MSG_PROGRESS_VALUE, 0, newpercent);
oldpercent = newpercent;
}
...
}
PostMessage(mainwnd, MSG_WORKER_DONE, 0, 0);
return 0;
}
...
MainWndProc(...) {
switch (uMsg) {
...
case MSG_PROGRESS_VALUE:
// update progress bar value (lParam)
break;
...
}
...
WinMain(...) {
HANDLE worker = CreateThread(NULL, 0, jobroutine, NULL, NULL, NULL);
...
// Start classic windows message loop
...
}

Related

How to make SDL_Keypress detect new Keypress during keypress-loop?

I'm writing Conways game of life in C with SDL. The game logic and everything works fine but I want to have it when you press p for example that the game automatically updates until p is pressed again and the loop stops. Somehow it only repeats once and doesn't even register the second time p is pressed.
else if (e.key.keysym.sym == SDLK_p){
bool stop = false;
while (!stop){
nextEpoch();
updateGame(window, renderer, r);
msleep(500);
if (e.type == SDL_KEYDOWN){
if (e.key.keysym.sym == SDLK_p){
stop = true;
printf("s\n");
}
}
}
}
It doesn't register that p is pressed when it in the while-loop.
Here's the full code: https://gist.github.com/PhilippRados/2df8760cc55822c2eac62addafb24403
As already pointed out by someone else in the comments section, you are not updating e in the inner loop. If you want to update e with a new event, you must call SDL_PollEvent( &e ) again to fill it with a new event.
In your linked code, you seem to be attempting to implement a new state of your program outside the main event loop, which represents the running state of the program, whereas the main event loop represents the paused state of the program. That way, you effectively have two separate event loops, one for each state of the program. While it is possible to make your program work this way, I don't recommend it.
For example, the way you have designed your program, your program won't respond to SDL_QUIT events in the running state. It will only do so in the paused state.
Therefore, it would make more sense to have a single event loop for both the running and the paused states of your program.
I don't recommend that you call usleep or SDL_Delay for waiting until it is time to render the next frame, as your program will not be responding to user input during this time. Especially since you have a very low frame rate of 2 frames per second, this means that it will take up to half a second for your program to respond to user input (for example if the user resizes the window or attempts to close it). Instead, I recommend that you set up a timer using SDL_AddTimer. You can program the timer callback function to give you a SDL_USEREVENT event twice per second. That way, when you receive this event, you will know that it is time to update the game and render the next frame. While waiting for this event, your program will still be able to respond to other events.
Note that in order to use SDL timers, you must initialize the corresponding subsystem using the SDL_INIT_TIMER flag when calling SDL_Init. Strangely, your linked code does not seem to call SDL_Init at all, so I am surprised that your code works at all. According to the documentation, you should call SDL_Init like this:
SDL_Init( SDL_INIT_TIMER | SDL_INIT_VIDEO );
Also, calling SDL_PollEvent in a loop seems like a big waste of CPU resources, as your CPU usage will likely be 100% although you are effectively doing nothing most of the time. I recommend that you call SDL_WaitEvent instead, so that the thread will sleep until it receives a new event to respond to.
Another thing worth noting is that when handling an SDL_MOUSEBUTTONDOWN event, it does not seem appropriate to use the result of SDL_GetMouseState to determine the coordinates of the mouse click, as that function will return the current mouse coordinates and not the coordinates at the time of the click. Therefore, it would be more appropriate to read these coordinates from the SDL_MouseButtonEvent structure.
Here is an example of how you could rewrite your event loop to use SDL_WaitEvent instead of SDL_PollEvent and to support both a running and a paused state in the main event loop.
Uint32 my_callbackfunc( Uint32 interval, void *param )
{
SDL_Event e;
e.user.type = SDL_USEREVENT;
e.user.code = 0;
e.user.data1 = NULL;
e.user.data2 = NULL;
SDL_PushEvent( &e );
return interval;
}
int main (int argc, char** argv)
{
[...]
//set timer to trigger twice per second
SDL_TimerID timer = SDL_AddTimer( 500, my_callbackfunc, NULL );
if ( timer == 0 ) {
//TODO: handle error
return EXIT_FAILURE;
}
//start game in a paused state
bool paused = true;
while ( SDL_WaitEvent( &e ) ) {
switch ( e.type ) {
case SDL_QUIT:
goto quit_game;
case SDL_WINDOWEVENT:
//rerender in case of window state change
updateGame( window, renderer, r );
break;
case SDL_USEREVENT:
if ( !paused ) {
nextEpoch();
updateGame(window, renderer, r);
}
break;
case SDL_MOUSEBUTTONDOWN:
mouseX = getNearestMultiple( e.button.x ) / RECT_SIZE;
mouseY = getNearestMultiple( e.button.y) / RECT_SIZE;
if ( Field[mouseX][mouseY] ) {
//Deactivate cell
Field[mouseX][mouseY] = false;
updateGame(window,renderer,r);
}
else {
//activate cell at position x,y
Field[mouseX][mouseY] = true;
updateGame(window,renderer,r);
}
break;
case SDL_KEYDOWN:
switch ( e.key.keysym.sym ) {
case SDLK_SPACE:
if ( paused ) {
nextEpoch();
updateGame(window, renderer, r);
}
break;
case SDLK_r:
memset(Field,0,sizeof(Field[0][0]) * WIDTH * HEIGHT);
memset(nextState,0,sizeof(nextState[0][0]) * WIDTH * HEIGHT);
updateGame(window,renderer, r);
break;
case SDLK_p:
paused = !paused;
}
}
}
quit_game:
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
}

Launch an application and wait until it has finished without blocking redraw

I have an interactive Win32 application and at some point I need to launch another application and wait until that other application has finished. During the time the other application runs, the interactive application shouldn't be responsive expect for resizing and moving the window (this implies of course that the interactive application still should continue redrawing).
My current approach is this:
Create a Thread T
Disable the main window (with EnableWindow(handle, FALSE))
Continue message loop
Special WM_APP message sent from thread T will enable the main window again (EnableWindow(handle, TRUE));
Thread T:
launch the application with CreateProcess
wait until application has terminated using WaitForSingleObject
post a special WM_APP message to the main window using PostMessage.
thread terminates here
This works fine, but I'm not sure if this is the correct approach.
Is there a better approach or should I continue like this?
Your approach is fine, just make sure to use PostMessage() for
send a special WM_APP message to the main window
to avoid deadlock if the main thread happens to wait for thread T.
As commenter noted, an alternative for creating a thread is to use a message loop with MsgWaitForMultipleObjectsEx.
The advantages I see:
There is no additional thread required, so there will be no worries about thread-related problems such as race conditions and deadlocks. These problems are often hard to find and debug (typically they only happen on customer machines), so I try to avoid threads as much as possible.
The program flow for creating the process and waiting for it is simpler. It can be sequential instead of event-based like the thread solution.
You have to judge for yourself if this is a better approach for your scenario.
A function that can be used to wait for a process (or any other waitable handle) while processing messages could be as follows. It's implementation is pretty involved (for background info see the links at the end of my answer) but usage is quite easy (see example afterwards).
// Function to process messages until the state of any of the given objects is signaled,
// the timeout is reached or a WM_QUIT message is received.
// Parameter hDialog can be nullptr, if there is no dialog.
//
// Returns ERROR_SUCCESS if any of the given handles is signaled.
// Returns ERROR_TIMEOUT in case of timeout.
// Returns ERROR_CANCELLED if the WM_QUIT message has been received.
// Returns the value of GetLastError() if MsgWaitForMultipleObjectsEx() fails.
DWORD WaitForObjectsWithMsgLoop(
HWND hDialog, const std::vector<HANDLE>& handles, DWORD timeOutMillis = INFINITE )
{
if( handles.empty() )
return ERROR_INVALID_PARAMETER;
DWORD handleCount = static_cast<DWORD>( handles.size() );
DWORD startTime = GetTickCount();
DWORD duration = 0;
do
{
DWORD status = MsgWaitForMultipleObjectsEx(
handleCount, handles.data(),
timeOutMillis - duration,
QS_ALLINPUT,
MWMO_INPUTAVAILABLE );
if( status == WAIT_FAILED )
{
// MsgWaitForMultipleObjectsEx() has failed.
return GetLastError();
}
else if( status >= WAIT_OBJECT_0 && status < WAIT_OBJECT_0 + handleCount )
{
// Any of the handles is signaled.
return ERROR_SUCCESS;
}
else if( status == WAIT_OBJECT_0 + handleCount )
{
// New input is available, process it.
MSG msg;
while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
if( msg.message == WM_QUIT )
{
// End the message loop because of quit message.
PostQuitMessage( static_cast<int>( msg.wParam ) );
return ERROR_CANCELLED;
}
// Enable message filter hooks (that's what the system does in it's message loops).
// You may use a custom code >= MSGF_USER.
// https://blogs.msdn.microsoft.com/oldnewthing/20050428-00/?p=35753
if( ! CallMsgFilter( &msg, MSGF_USER ) )
{
// Optionally process dialog messages.
if( ! hDialog || ! IsDialogMessage( hDialog, &msg ) )
{
// Standard message processing.
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
}
}
duration = GetTickCount() - startTime;
}
while( duration < timeOutMillis );
// Timeout reached.
return ERROR_TIMEOUT;
}
The function could be used in a dialog box procedure as follows. Error handling omitted for brevity.
INT_PTR CALLBACK YourDialogProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
static bool s_childProcessRunning = false;
switch( message )
{
case YourMessageToLaunchProcess:
{
// prevent reentrancy in case the process is already running
if( s_childProcessRunning )
{
MessageBoxW( hDlg, L"Process already running", L"Error", MB_ICONERROR );
return TRUE;
}
// Prepare CreateProcess() arguments
STARTUPINFO si{ sizeof(si) };
PROCESS_INFORMATION pi{};
wchar_t command[] = L"notepad.exe"; // string must be writable!
// Launch the process
if( CreateProcessW( NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ) )
{
// Set flag to prevent reentrancy.
s_childProcessRunning = true;
// Wait until the child process exits while processing messages
// to keep the window responsive.
DWORD waitRes = WaitForObjectsWithMsgLoop( hDlg, { pi.hProcess } );
// TODO: Check waitRes for error
s_childProcessRunning = false;
// Cleanup
CloseHandle( pi.hThread );
CloseHandle( pi.hProcess );
}
return TRUE;
}
// more message handlers...
}
return FALSE;
}
Obligatory Old New Thing links:
Pumping messages while waiting for a period of time
The dialog manager, part 4: The dialog loop
Rescuing thread messages from modal loops via message filters

GtkSpinner with long-lasting function with C

I'm making a GTK+3 application in C and I want a spinner to show when the program is processing the data. Here's what I generally have:
main()
{
//Some statements
g_signal_connect(G_OBJECT(btnGenerate), "clicked", G_CALLBACK(Generate), &mainform);
}
void Generate(GtkWidget *btnGenerate, form_widgets *p_main_form)
{
gtk_spinner_start(GTK_SPINNER(p_main_form->spnProcessing));
Begin_Lengthy_Processing(Parameters, Galore, ...);
//gtk_spinner_stop(GTK_SPINNER(p_main_form->spnProcessing));
}
I have the stop function commented out so I can see the spinner spin even after the function has finished, but the spinner starts after the function is finished, and I suspect it turns on in the main loop.
I also found out that the entire interface freezes during the execution of the long going function.
Is there a way to get it to start and display inside the callback function? I found the same question, but it uses Python and threads. This is C, not Python, so I would assume things are different.
You need to run your lengthy computation in a separate thread, or break it up into chunks and run each of them separately as idle callbacks in the main thread.
If your lengthy computation takes a single set of inputs and doesn’t need any more inputs until it’s finished, then you should construct it as a GTask and use g_task_run_in_thread() to start the task. Its result will be delivered back to the main thread via the GTask’s GAsyncReadyCallback. There’s an example here.
If it takes more input as it progresses, you probably want to use a GAsyncQueue to feed it more inputs, and a GThreadPool to provide the threads (amortising the cost of creating threads over multiple calls to the lengthy function, and protecting against denial of service).
The GNOME developer docs give an overview of how to do threading.
This is what I got:
int main()
{
// Statements...
g_signal_connect(G_OBJECT(btnGenerate), "clicked", G_CALLBACK(Process), &mainform);
// More statements...
}
void Process(GtkWidget *btnGenerate, form_widgets *p_main_form)
{
GError *processing_error;
GThread *start_processing;
gtk_spinner_start(GTK_SPINNER(p_main_form->spnProcessing));
active = true;
if((start_processing = g_thread_try_new(NULL, (GThreadFunc)Generate, p_main_form, &processing_error)) == NULL)
{
printf("%s\n", processing_error->message);
printf("Error, cannot create thread!?!?\n\n");
exit(processing_error->code);
}
}
void Generate(form_widgets *p_main_form)
{
// Long process
active = false;
}
My program, once cleaned up and finished, as there are many other bugs in the program, will be put on GitHub.
Thank you all for your help. This answer comes from looking at all of your answers and comments as well as reading some more documentation, but mostly your comments and answers.
I did something similar in my gtk3 program. It's not that difficult. Here's how I would go about it.
/**
g_idle_add_full() expects a pointer to a function with the signature below:
(*GSourceFunc) (gpointer user_data).
So your function signature must adhere to that in order to be called.
But you might want to pass variables to the function.
If you don't want to have the variables in the global scope
then you can do this:
typedef struct myDataType {
char* name;
int age;
} myDataType;
myDataType person = {"Max", 25};
then when calling g_idle_add_full() you do it this way:
g_idle_add_full(G_PRIORITY_HIGH_IDLE, myFunction, person, NULL);
*/
int main()
{
// Assumming there exist a pointer called data
g_idle_add_full(G_PRIORITY_HIGH_IDLE, lengthyProcessCallBack, data, NULL);
// GTK & GDK event loop continues and window should be responsive while function runs in background
}
gboolean lengthyProcessCallBack(gpointer data)
{
myDataType person = (myDataType) *data;
// Doing lenghthy stuff
while(;;) {
sleep(3600); // hypothetical long process :D
}
return FALSE; // removed from event sources and won't be called again.
}

sending messages to the main window in a thread in win32

I am relatively new to working with threads in Win32 api and have reached a problem that i am unable to work out.
Heres my problem, i have 4 threads (they work as intended) that allow the operator to test 4 terminals. In each thread i am trying to send a message to the main windows form with either Pass or Fail, this is placed within a listbox. Below is one of the threads, the remaining are exactly the same.
void Thread1(PVOID pvoid)
{
for(int i=0;i<numberOfTests1;i++) {
int ret;
double TimeOut = 60.0;
int Lng = 1;
test1[i].testNumber = getTestNumber(test1[i].testName);
unsigned char Param[255] = {0};
unsigned char Port1 = port1;
ret = PSB30_Open(Port1, 16);
ret = PSB30_SendOrder (Port1, test1[i].testNumber, &Param[0], &Lng, &TimeOut);
ret = PSB30_Close (Port1);
if(*Param == 1) SendDlgItemMessage(hWnd,IDT_RESULTLIST1,LB_ADDSTRING,i,(LPARAM)"PASS");
else SendDlgItemMessage(hWnd,IDT_RESULTLIST1,LB_ADDSTRING,i,(LPARAM)"FAIL");
}
_endthread();
}
I have debugged the code and it does everything except populate the listbox, i assume because its a thread i am missing something as the same code works outwith the thread. Do i need to put the thread to sleep while it sends the message to the main window?
Any help is appreciated.
Cheers
You don't want your secondary threads trying to manipulate your UI elements directly (such as the SendDlgItemMessage). Instead, you normally want to post something like a WM_COMMAND or WM_USER+N to the main window, and let that manipulate the UI elements accordingly.

Gracefully closing a windowless app in WinAPI

I'm writing a little utility app to control the system master volume via hotkeys for my GF, whose laptop is for some reason deprived of such function keys. I whipped up the code pretty much instantly and I've got the main functionality working perfectly; however, since I'm not creating any windows (just a message loop handling the WM_HOTKEY message), I can't terminate the app in a more elegant manner than just gracelessly terminating the process (also, when the system is shutting down, it shows the "should I wait for the process to end or kill it now" window with some rubbish in the place where the window title usually is).
Is there any way of doing this which doesn't involve creating a fake window just for the sake of intercepting WM_CLOSE messages?
Here's the code (I left out the mixer control functions intentionally, they're irrelevant to the question):
int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow) {
MSG msg;
int step;
MixerInfo_t mi;
HANDLE mutex;
mutex = CreateMutex(NULL, TRUE, "volhotkey");
if (mutex == NULL)
return 1;
if (GetLastError() == ERROR_ALREADY_EXISTS)
return 0;
RegisterHotKey(NULL, 1, MOD_ALT | MOD_CONTROL, VK_F5);
RegisterHotKey(NULL, 2, MOD_ALT | MOD_CONTROL, VK_F6);
RegisterHotKey(NULL, 3, MOD_ALT | MOD_CONTROL, VK_F7);
mi = GetMixerControls();
step = (mi.maxVolume - mi.minVolume) / 20;
while (GetMessage(&msg, NULL, 0, 0)) {
switch (msg.message) {
case WM_HOTKEY:
switch (msg.wParam) {
case 1:
AdjustVolume(&mi, -step);
break;
case 2:
AdjustVolume(&mi, step);
break;
case 3:
SetMute(&mi, !IsMuted(&mi));
break;
}
MessageBeep(MB_ICONASTERISK);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
break;
}
}
UnregisterHotKey(NULL, 1);
UnregisterHotKey(NULL, 2);
return msg.wParam;
}
Thanks in advance!
Oh, and for the record, WM_DESTROY is also never posted.
You could use the SetConsoleCtrlHandler() function to listen for the shutdown event.
SetConsoleCtrlHandler( ShutdownHandler, TRUE );
You handler would look something like this:
BOOL WINAPI ShutdownHandler( DWORD dwCtrlType )
{
if( dwCtrlType == CTRL_SHUTDOWN_EVENT || dwCtrlType == CTRL_LOGOFF_EVENT )
{
ExitProcess( 0 );
return TRUE; // just to keep the compiler happy
}
return FALSE;
}
Despite the name, SetConsoleCtrlHandler() works regardless of whether or not the application is a console application.
Have a look at the ExitProcess API call for shutting down a process gracefully. To detect a Windows shutdown, include WM_ENDSESSION in your message handling. If your application is more complex than what is posted, you may also want to review the ExitThread function.
You didn't create any window, not even a hidden one, so there's no way to get the loop to exit by sending a message to a window. Also the reason that WM_DESTROY never fires.
All that's left is PostThreadMessage() to post WM_QUIT. You'd have to be able to find the thread ID somehow. Using Shell_NotifyIcon() would be wise.
You could always show something in the system tray easily enough from which you could elegantly close it. And as your application grows, that may be desirable, because the user may eventually want to be able to configure or change the hotkeys, or temporarily turn them off it they interfere with another application etc.
Or have another hotkey which shows a small window with configuration options?

Resources