Thread: Need help with multithreading in win32 c programming

  1. #1
    Registered User
    Join Date
    Jan 2013
    Posts
    4

    Need help with multithreading in win32 c programming

    I hope I can exlplain what my problem is without posting any code, as it is a complete mess right now. Disclaimer: I'm very new to win32 C programming.

    I have a window that has a "batch" button on it. When the user clicks that button, it spawns off a process that loops through a file (sometimes a big one) and processes records from the file. If the user clicks "batch" and soon decides that he didn't want to do that, or the file is too big and it's just taking too long, I want him to be able to click a "cancel" processing button.

    So I assumed the solution to this would be to create a modeless dialog box in a separate thread. The dialog box will show the progress of the processing of the file, and also have a "cancel processing" button that the user can click if he wants to stop the process. If the user clicks the "cancel processing" button, a global flag will be set, and the main processing window will check this flag before it processes each record to decide if it needs to continue or stop.

    Now here's the problem. On the click of the "batch" button, I start a procedure in a new thread using _beginthreadex. This procedure creates the modeless dialog box and has a message loop in it that monitors any clicks on dialog box. But it doesn't appear that this procedure starts until all the messages on the main window that were triggered by the "batch" button click are finished. I run the program in debug mode in Visual Studio and put a breakpoint on the _beginthreadex line. I step line by line past it, and the dialog box doesn't appear. Only when I continue and it finishes the "batch" button process does the dialog box appear. Of course, I need for the dialog box to immediately appear after the call to _beginthreadex, or else the file processing will complete, and the user will have no chance to cancel it. Does a thread started by _beginthreadex not start immediately, and start sharing CPU time with the main thread? Does it only start once the process that issued the _beginthreadex (click of "batch" button) has completed?

    Any help or advice on this would be greatly appreciated.
    Last edited by mlf; 01-18-2013 at 12:29 PM.

  2. #2
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Are you creating the dialog from the main thread or the new thread? It needs to be created from the same thread the messages will be processed on. It sounds like what is happening is you've created the dialog from the main thread, so the new thread never pumps messages and it's actually the main thread processing them after the batch operation completes.

    But this whole design seems backward -- shouldn't it be the new thread that handles the record processing, while the main thread handles the dialog?
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  3. #3
    Registered User
    Join Date
    Jan 2013
    Posts
    4
    The dialog is being created by the new Thread. As I said, I start a procedure in a new thread, and that procedure itself starts the dialog, and it also has a message processing loop for the dialog. The dialog works fine (once it shows up). That's not the issue. The issue is it doesn't appear immediately after I issue the _beginthreadex.

    Yeah, the process might seem backwards. But I'm only making a modification to an existing program that was written by someone else. The program is somewhat of a mess, so it might be an enormous amount of work to do it any differently than what I'm trying to do now.


    Quote Originally Posted by brewbuck View Post
    Are you creating the dialog from the main thread or the new thread? It needs to be created from the same thread the messages will be processed on. It sounds like what is happening is you've created the dialog from the main thread, so the new thread never pumps messages and it's actually the main thread processing them after the batch operation completes.

    But this whole design seems backward -- shouldn't it be the new thread that handles the record processing, while the main thread handles the dialog?

  4. #4
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    I think that this thread should be moved to Windows topic

    There might be someone who can help you who doesn't look at the C topic
    Fact - Beethoven wrote his first symphony in C

  5. #5
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Use events and wait objects.

    Use CreateEvent() to create a 'cancel' event, create it set to 'not_cancelled' (ie false). Do this before you start the thread working.

    Make the thread periodically check for the 'cancel' event (ie each record) with WaitForSingleObject() in the thread processing function.

    If the user cancels the processing use SetEvent() to change the cancel event to 'canceled' (ie true).

    If the thread finds it has been canecled call the threads clean up code etc.

    Here is some code;

    Windows SDK Thread: How to end a thread?

    Another way is a mutex.

    Create a global (in C) variable that the parent dialog and thread can access.
    The parent dlg sets it to cancelled, and the thread periodically checks the value.

    This requires critical sections to ensure only one thread can access this variable at one time.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Moved to Windows programming forum.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Jan 2013
    Posts
    4
    Thanks for the suggestion novacain. I tried that though, and seem to be having the same problem. Again, the problem appears to be my new thread is NOT starting immediately and gaining CPU time. It only starts after the code that gets executed (processing of the file) when the user clicks the "batch" button. Here is a scaled down version of some of my code that might help explain the problem.

    First off, I'm coding in C in Visual Studio 2005.

    The user clicks a "batch" button on a window and this code starts

    Code:
    /* 
    *
    * some code here
    * 
    */
    CASE IDM_BATCH
    ghCancelEvent = CreateEvent(NULL, TRUE, FALSE, TEXT("CancelEvent"));
    CreateThread(NULL, 0, startBatchStatus, NULL, 0, &dwThreadID);
    /*
    *
    * code to process file of records
    *
    *
    */
    Here is the thread procedure startBatchStatus:

    Code:
    DWORD WINAPI startBatchStatus( void )
    {
    /*
    *
    * some code here
    *
    */
    hwndStatThread = CreateDialog(ghInstance, "Batch_Status", hComWnd, BatchStatusDlgProc); 
    while(GetMessage(&Msg, hwndStatThread, 0, 0) > 0)
    {
    TranslateMessage(&Msg);
    DispatchMessage(&Msg);
    }
    }
    Here is code that handles messages to the dialog:

    Code:
    BOOL CALLBACK BatchStatusDlgProc( HWND hDlg, UINT wMessage, WPARAM wParam, LPARAM lParam )
    {
    /*
    *
    * some code here
    *
    *
    */
    case IDC_CANCEL :
    MessageBox( NULL, "Canceled process", "User Error", MB_SYSTEMMODAL | MB_ICONHAND | MB_OK );
    gbCancel_Button = TRUE;
    EndDialog ( hDlg, 0 );
    return( 0 );
    break;
    /*
    *
    * some code here
    *
    *
    */
    
    }
    The dialog eventually appears, but only after the code to process the records is complete. And when I click the cancel button on the dialog, the dialog ends properly, so the message loop is working properly. I even put a Sleep(10000); and break; immediately after the CreateThread() command to eliminate the file processing code altogether, and sure enough, there's about a 10 second pause after you click the "batch" button, then the dialog appears. In other words, the dialog didn't appear until the Sleep() and break commands were finished.

    So I'm pretty much back to my original question. When you create a new thread in a block of code, whether using CreateThread() or _beginthreadex(), does the thread start IMMEDIATELY after you issue the command and start sharing CPU time with the main thread? It certainly doesn't appear so in my case. I would think that what I'm trying to do (start a long process and provide a dialog to cancel it) would be a pretty common thing. But it's driving me nuts.





    Quote Originally Posted by novacain View Post
    Use events and wait objects.

    Use CreateEvent() to create a 'cancel' event, create it set to 'not_cancelled' (ie false). Do this before you start the thread working.

    Make the thread periodically check for the 'cancel' event (ie each record) with WaitForSingleObject() in the thread processing function.

    If the user cancels the processing use SetEvent() to change the cancel event to 'canceled' (ie true).

    If the thread finds it has been canecled call the threads clean up code etc.

    Here is some code;

    Windows SDK Thread: How to end a thread?

    Another way is a mutex.

    Create a global (in C) variable that the parent dialog and thread can access.
    The parent dlg sets it to cancelled, and the thread periodically checks the value.

    This requires critical sections to ensure only one thread can access this variable at one time.

  8. #8
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    Usually you create a thread to do the long running process, and leave the UI thread to, well, handle UI rather than vice-versa.

    As for threads, they're non-deterministic. They might start before CreateThread returns, or if you do something cpu-intensive they may take an age to start. If you want the thread to 'start' before the CreateThread-ing code resumes its job, you have to code that in using events or other thread safe means to communicate.

  9. #9
    Registered User
    Join Date
    Jan 2013
    Posts
    4
    Thanks adeyblue. I know what you are saying about putting the long processing in the new thread. But unfortunately, this program was already written, and all I'm doing is adding the "cancel" dialog. The long processing code is running in the main thread and it is structured in such a way and bounces all over the place, that it is not really an option for me to put that in the new thread.

    And I know what your saying about threads being unpredictable. But I changed the sleep to Sleep(90000), and the main thread literally sits there a full minute before the dialog pops up. Not only is the main thread at that time not doing anything CPU intensive, it is not doing anything at all (but sleeping). If the new thread can't get CPU time when the main thread is sleeping, I don't know when it can. That just doesn't make sense.

    I even tried creating the cancel event and new thread at the time the main window is created. I set the initial state of the cancel event to unsignaled and put a waitforsingleobject in the new thread code to wait for the event to be signaled before displaying the dialog window. Then I put a SetEvent of the cancel event inside the "batch" button code with the Sleep after it. Same thing. After the sleep is finished in about 1 minute, the dialog appears. Even though the new thread has long been created at that point and is waiting on the event to be signaled before it displays the dialog, it still doesn't display it immediately when I issue the SetEvent command. It waits until the sleep is done and the "batch" button code is finished.

    Any specific suggestions on what I can try? Is there some sort of way to see the priority to the new thread when I first start it?

    Quote Originally Posted by adeyblue View Post
    Usually you create a thread to do the long running process, and leave the UI thread to, well, handle UI rather than vice-versa.

    As for threads, they're non-deterministic. They might start before CreateThread returns, or if you do something cpu-intensive they may take an age to start. If you want the thread to 'start' before the CreateThread-ing code resumes its job, you have to code that in using events or other thread safe means to communicate.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 4
    Last Post: 12-11-2011, 04:25 PM
  2. win32 programming
    By iggypop in forum Networking/Device Communication
    Replies: 1
    Last Post: 01-29-2011, 08:53 AM
  3. Replies: 2
    Last Post: 10-13-2004, 06:48 AM
  4. Win32 programming, help please...
    By Finchie_88 in forum C++ Programming
    Replies: 2
    Last Post: 10-05-2004, 04:14 PM
  5. Win32 Programming
    By GreenCherry in forum C++ Programming
    Replies: 4
    Last Post: 11-05-2002, 04:14 PM