How to create and run threads in Virtual C++ 2008 Express?

Hello!

Can anyone please give me a guide of how I create and run threads in Virtual C++ 2008 Express?
I want to create a new thread everytime I play an audio file. The audio file is played when the user clicks certain buttons in the GUI.

Thanks!

Anders Branderud
http://bloganders.blogspot.com
AndersBranderudAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

evilrixSenior Software Engineer (Avast)Commented:
Take a look at CreateThread

http://msdn.microsoft.com/en-us/library/ms682453(VS.85).aspx
#include <windows.h>
#include <process.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
 
HANDLE hWaitEvent1 = CreateEvent(0, true, true, 0);
HANDLE hStopEvent = CreateEvent(0, true, false, 0);
 
DWORD WINAPI ThreadProc(void * lpParameter)
{
        puts("Thread starting");
 
        for(;;)
        {
                // If signaled then break
                if(0 == WaitForSingleObject(hStopEvent, 0)) { break; }
 
                // If not signaled then wait indefinately
                WaitForSingleObject(hWaitEvent1, INFINITE);
 
                // Some IO for th euser
                puts("Thread running");
 
                // Give other threads/processes a chance
                ::Sleep(500);
        }
 
        puts("Thread stopped");
 
        return 0;
}
 
int main()
{
        HANDLE hThread = CreateThread(0, 0, ThreadProc, 0, 0, 0);
 
        system("pause");
        ResetEvent(hWaitEvent1); // Signal thread to pause
 
        system("pause");
        SetEvent(hWaitEvent1); // Signal thread to unpause
 
        system("pause");
        SetEvent(hStopEvent); // Signal thread to stop
 
        WaitForSingleObject(hThread, INFINITE); // Wait for thread to terminate
        system("pause");
}

Open in new window

0
itsmeandnobodyelseCommented:
@evilrix: the question was an add-on from (http:Q_25746943.html)

Assuming you now have a handler like

void MyForm::OnClickedPlay()
{
     playAudio();
}

which was playing the audio but blocks all further messages to be processed, you could do

void MyForm::OnClickedPlay()
{
     _beginthread(playAudioStatic, 0, this);
}

instead, where playAudioStatic is a static member of your MyForm class like

class MyForm : public ....
{
    ....
public:
    // a static member function can be passed as function pointer to beginthread
    static void playAudioStatic(void* p)
    {
          MyForm* pThis = (MyForm*)p;
          pThis->playAudio();
    }
    ....
private:
    bool m_isStopped;
    int    m_progress;
    ...
};

The above shows how you could call a (existing) member function of your GUI class via thread asynchronously.

But, the playAudio() function should do any GUI stuff, e. g. it shouldn't refresh the screen and shouldn't set values to controls, nothing what would send or generate a message to the message loop of the GUI. Instead it should/could fill member variables which periodically could evaluated and displayed by the GUI (main thread)

void MyForm::playAudio()
{
     ....
     // check a stop flag which can be set from main GUI
     while (!m_isStopped)
     {
           ....
           // calculate progress
           m_progress = ((maxtime - elapsedtime)*100) / maxtime;
           // play a further part ....
           ....
     }
}

// that's a GUI timer
void MyForm::OnTimer(unsigned int timerEvt)
{
      if (timerEvt == 1)  // assume you created the timer with event 1
      {
            showProgress(m_progress);  // here evaluate the progress set by the thread
      }
}

// cancel handler
void MyForm::OnCancel()
{
     // stop the thread
     m_isStopped = false;
     // wait some time for recognizing
     Sleep(1000);  // waits  a second
     EndDialog(IDCANCEL);
}
0
itsmeandnobodyelseCommented:
>>>> But, the playAudio() function should do any GUI stuff

Means:
   But, the playAudio() function should NOT do any GUI stuff
0
The Ultimate Tool Kit for Technolgy Solution Provi

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy for valuable how-to assets including sample agreements, checklists, flowcharts, and more!

evilrixSenior Software Engineer (Avast)Commented:
>> @evilrix: the question was an add-on from (http:Q_25746943.html)
Thanks for the additional info Alex. It would have been helpful were that stated in the question :)
0
itsmeandnobodyelseCommented:
@Anders: What GUI library you were using? Is it qt ?

0
AndersBranderudAuthor Commented:
Thanks!
I create a thread. I run it. The music plays. I signal through a global variable that music has finished playing.

In the GUI I run a while loop that reads this global variable. It runs a for loop 100 laps and after 100 laps it sleeps for 200 milli seconds.

When the finished_playing-variable is set to 0, it does break from the while loop, and then it runs this code:

system("pause");
 ResetEvent(hWaitEvent1); // Signal thread to pause
 
system("pause");
 SetEvent(hWaitEvent1); // Signal thread to unpause

When/close to when the play music-thread has finished running its code the application hangs.
A dialog box is shown that says: "Ljudtestet3.exe has stopped working"

Anders Branderud
http://bloganders.blogspot.com
0
evilrixSenior Software Engineer (Avast)Commented:
>>  When the finished_playing-variable is set to 0, it does break from the while loop

Some of the code in my example was only intended to give you an insight into a thread working and isn't necessary to be part of a complete solution. If you can post what you have so far we can probably help you fix it up.
0
itsmeandnobodyelseCommented:
>>>> In the GUI I run a while loop that reads this global variable. It runs a for loop 100 laps and after 100 laps it sleeps for 200 milli seconds.

The loop and the sleeping would prevent the GUI processing messages same as the audio-play.

Note, a normal GUI would run an infinite message loop like

  while (PeekMessage(Msg) != WM_QUIT)
  {
        GetMessage(Msg);
        TranslateMessage(Msg);
        DispatchMessage(Msg);
  }

The PeekMessage peeks for new messages and has a little sleeping so that it doesn't eat all CPU.

The GetMessage gets the message.

The TranslateMessage does some pretranslating such as hotkeys.

The DispatchMessage finally calls the predefined handler functions, e. g. after a button click.

If you call some lengthy thing from your handler the whole loop is blocked and the screen freezes because no more messages were processed.

If you were running an application framework of a GUI library (such as qt or MFC) your only thing to do is to provide the handler functions which were called from DispatchMessage.

You never should make a system("pause"); cause that would only work in a console program but not in a windows application. You also must not make big loops and sleeps from a handler but only run very short time and put new messages to the message pump by calling SendMessage (immediately invoked) or PostMessage (deferred invoked).  

What kind of GUI do you have currently?

>>>> When/close to when the play music-thread has finished running its code the application hangs.

The thread will finish when the return of the thread function passed to CreateThread (or _beginthread)  was executed. So, when you recognized the global (or shared) flag and break the playing loop then and return, all is fine. Moreover, even if the thread wasn't finished it would make your application hang cause it was killed finally with your main thread (process). So, if it hangs it was because of your main thread which probably didn't recognize that the thread has finished. You may think of a second flag (event) or use the thread-handle to wait for by calling WaitForMultipleObjects (the WaitForSingleObject is not senseful if running the GUI loop cause it blocks all message handling as well). WaitForMultipleObjects can be called in a loop so that you either get the signal of the thread to be finished or that you get signalled that messages need to be processed.  


0
AndersBranderudAuthor Commented:
@itsmeandnobodyelse:
I have an Windows Forms-application.
I tried your solution but I got an error-message ("error C2665: '_beginthread' : none of the 2 overloads could convert all the argument types").

Then I  Googled the error message and found a topic on this website: http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/8f19cdf1-0c0f-4fb4-898c-896dd094f50b

One reply starts: "You cannot cast a void* to a managed class reference.  You should not use _beginthreadex() in managed code, you should use the System::Threading::Thread class. "

I tried the code presented in that post and it worked.
The only disadvantage is that while the audio file is playing and when I move the GUI-window it says "GUI not responding").

I would be glad if anyone could provide me a solution that enables the movement of the GUI-window without generating the "Not responding"-label in the top of the GUI.

The solution should work in Visual C++ 2008 Express Edition.

Anders Branderud
http://bloganders.blogspot.com
0
AndersBranderudAuthor Commented:
itsmeandnobodyelse:
Thanks for your lengthy and clarifying response!

I will try to use WaitForMultipleObjects.


Anders Branderud
http://bloganders.blogspot.com
0
itsmeandnobodyelseCommented:
>>>> I have an Windows Forms-application

But Windows Forms is managed C++, right? If so, the code samples wouldn't work so easily cause you would need a mixed-code assembly for that and always switch between managed and unmanaged. Note the CreateThread and _beginthread is unmanaged C++ and accepts only function pointers to unmanaged C++ functions. So you can't pass 'this' pointer of a managed object but would need an unmanaged helper class which could be used both from (unmanaged) thread and managed Windows Forms class.

Unfortunately I have only a vague idea how that could be coded in a mixed assembly.

Probably you firstly check whether your class library has a managed CreateThread function (probably below System namespace). If so, you should take this rather than switching to unmanaged code. The concepts both from evilrix and me still were valid but the system functions were differently then.  

Also I am pretty sure that the Windows Forms has a built-in timer function which you simply can overload  and where you could monitor/show the progress made.
0
itsmeandnobodyelseCommented:
>>>> you should use the System::Threading::Thread class.

Yeah, I didn't read that before. That exactly is the way to go.
0
itsmeandnobodyelseCommented:
>>>> I tried the code presented in that post and it worked.
What is the code that worked?
0
AndersBranderudAuthor Commented:
I programmed this below code before reading itsmeandnobodyelse last replies.
I compile using the /clr-problem, so maybe no problem is caused of me using a mixture of unmanaged and managed code.

I used some of this code: http://msdn.microsoft.com/en-us/library/ms687055(v=VS.85).aspx

I attach some of the program code that I have written.
The program runs, the thread starts, but shortly after the audio file has finished playing I get the same error as I mentioned before.

Why is that error caused?

Is it possible to use the code I attach although I have managed C++?
I use WaitForMultipleObjects(), but I don't understand what other event that I should signal to. And from where I shall signal to it?

Thanks!

Anders Branderud
http://bloganders.blogspot.com
DWORD WINAPI ThreadProc(void * lpParameter)
{
	    // int *value;
			 // value = reinterpret_cast<int*> (args);
        MessageBox::Show (L"Thread starting..", L"inside of thread task....", MessageBoxButtons::OK,MessageBoxIcon::Exclamation);	
 
        	// Some IO for th euser
         if ( failed_to_delete_file_ending_int == 0 )
					 PlaySound ( L"ljudfiler/output0.wav", NULL,SND_SYNC); //Synchronous playback..Returns after sound event complete.
         else if ( failed_to_delete_file_ending_int == 1 )
					 PlaySound ( L"ljudfiler/output1.wav", NULL,SND_SYNC); 
				 else if ( failed_to_delete_file_ending_int == 2 )
					 PlaySound ( L"ljudfiler/output2.wav", NULL,SND_SYNC); 
				 else if ( failed_to_delete_file_ending_int == 3 )
					 PlaySound ( L"ljudfiler/output3.wav", NULL,SND_SYNC); 
				 else if ( failed_to_delete_file_ending_int == 4 )
					 PlaySound ( L"ljudfiler/output5.wav", NULL,SND_SYNC); 
				 else if ( failed_to_delete_file_ending_int == 5 )
					 PlaySound ( L"ljudfiler/output5.wav", NULL,SND_SYNC); 
				 else if ( failed_to_delete_file_ending_int == 6 )
					 PlaySound ( L"ljudfiler/output6.wav", NULL,SND_SYNC); 
				 else if ( failed_to_delete_file_ending_int == 7 )
					 PlaySound ( L"ljudfiler/output7.wav", NULL,SND_SYNC); 
				 else if ( failed_to_delete_file_ending_int == 8 )
					 PlaySound ( L"ljudfiler/output8.wav", NULL,SND_SYNC); 
				 else if ( failed_to_delete_file_ending_int == 9 )
					 PlaySound ( L"ljudfiler/output9.wav", NULL,SND_SYNC); 
                // If signaled then break
        
				 int failed_event;
				 int nr_of_fails;
				 nr_of_fails=0;
				 failed_event = SetEvent (ghEvents[0] );
				 while ( !failed_event)
				   {
           failed_event = SetEvent (ghEvents[0] );

					 nr_of_fails++;
					 
					 if(nr_of_fails == 5)
						 break;
				   }

				 audio_file_is_playing =false; //loop will terminate in gui thread..
         
 
       MessageBox::Show (L"Thread stopped..", L"inside of thread task....", MessageBoxButtons::OK,MessageBoxIcon::Exclamation);	
 
        return 0;
}

//From function in GUI:

 //CREATE THREAD.

         if (error_nr_of_times == 0 )
				   {
				   hThread = CreateThread (0,0,(LPTHREAD_START_ROUTINE) ThreadProc(NULL), 0,0 ,0);   
           
					 while (hThread == 0 )
					   {
             hThread = CreateThread (0,0,(LPTHREAD_START_ROUTINE) ThreadProc(NULL), 0,0 ,0);   

						 error_nr_of_times++;
						 Sleep (20);
						 if (error_nr_of_times == 5)
							 break;
					   }
					 if (hThread != 0)
						 error_nr_of_times=0;

				   }

				 if (hThread == 0) //Run music in this thread.
					 playAudioInThisThread ();
				 else //we have a hThread
				   {
           dwEvent = WaitForMultipleObjects (1,ghEvents, FALSE, 16000);
				   }

Open in new window

0
AndersBranderudAuthor Commented:
Sorry that the code was messy.
It got messed up when I copied it.
Here it follows again (I fixed it some also.)

Anders Branderud
http://bloganders.blogspot.com
DWORD WINAPI ThreadProc(void * lpParameter)
      {
	  
     MessageBox::Show (L"Thread starting..", L"inside of thread task....", MessageBoxButtons::OK,MessageBoxIcon::Exclamation);	

    	// Some IO for th euser
     if ( failed_to_delete_file_ending_int == 0 )
				 PlaySound ( L"ljudfiler/output0.wav", NULL,SND_SYNC); //Synchronous playback..Returns after sound event complete.
     else if ( failed_to_delete_file_ending_int == 1 )
				 PlaySound ( L"ljudfiler/output1.wav", NULL,SND_SYNC); 
	 else if ( failed_to_delete_file_ending_int == 2 )
		 PlaySound ( L"ljudfiler/output2.wav", NULL,SND_SYNC); 
	 else if ( failed_to_delete_file_ending_int == 3 )
		 PlaySound ( L"ljudfiler/output3.wav", NULL,SND_SYNC); 
	 else if ( failed_to_delete_file_ending_int == 4 )
		 PlaySound ( L"ljudfiler/output5.wav", NULL,SND_SYNC); 
	 else if ( failed_to_delete_file_ending_int == 5 )
		 PlaySound ( L"ljudfiler/output5.wav", NULL,SND_SYNC); 
	 else if ( failed_to_delete_file_ending_int == 6 )
		 PlaySound ( L"ljudfiler/output6.wav", NULL,SND_SYNC); 
	 else if ( failed_to_delete_file_ending_int == 7 )
		 PlaySound ( L"ljudfiler/output7.wav", NULL,SND_SYNC); 
	 else if ( failed_to_delete_file_ending_int == 8 )
		 PlaySound ( L"ljudfiler/output8.wav", NULL,SND_SYNC); 
	 else if ( failed_to_delete_file_ending_int == 9 )
		 PlaySound ( L"ljudfiler/output9.wav", NULL,SND_SYNC); 
       // If signaled then break

	 int failed_event;
	 int nr_of_fails;
	 nr_of_fails=0;
	 failed_event = SetEvent (ghEvents[0] );
			 
	 while ( !failed_event)
	   {
           failed_event = SetEvent (ghEvents[0] );

	   nr_of_fails++;
				 
	   if(nr_of_fails == 5)
	     break;
	   } 

   MessageBox::Show (L"Thread finished...", L"Thread finished..", MessageBoxButtons::OK,MessageBoxIcon::Exclamation);	
   return 0;
   }

Open in new window

0
AndersBranderudAuthor Commented:
One more comment: I forgot to remove the "//-tags". They are not correct for the above code.
0
itsmeandnobodyelseCommented:
>>>> dwEvent = WaitForMultipleObjects (1,ghEvents, FALSE, 16000);

As told calling of the wait functions would freeze your GUI.

You must not wait here for the thread to terminate. Simply return.

Also remove the SetEvent and the while loop around from the audio thread. Simply set a global shared flag 'threadIsRunning' to false. When you create the thread (or in the ThreadProg) set the 'threadIsRunning to true.

Note, the code from evilrix wasn't made for a GUI program but for a console program. There you would need top wait in the main function (main thread) until the thread finished cause returning from main would exit the program.

0
AndersBranderudAuthor Commented:
"As told calling of the wait functions would freeze your GUI.

You must not wait here for the thread to terminate. Simply return.

Also remove the SetEvent and the while loop around from the audio thread. Simply set a global shared flag 'threadIsRunning' to false. When you create the thread (or in the ThreadProg) set the 'threadIsRunning to true.

Note, the code from evilrix wasn't made for a GUI program but for a console program. There you would need top wait in the main function (main thread) until the thread finished cause returning from main would exit the program. "

I have implemented this now, but for some reasons the GUI still does not work as it should when a file is played and after the file has finished playing the program gets an error ("Ljudtestet3.exe has stopped working")

I create a new thread. It runs. It completes. It returns to the caller-thread (I checked this temporarily by displaying a messagebox). After it has returned I get the error "Ljudtestet3.exe has stopped working".

Any idea of what goes wrong?

I testet to remove the sound playing code, and instead inserted a loop doing some maths. The GUI freezes during the time it does that. And after the return from
the thread doing the maths I receive the same error "Ljudtestet3.exe has stopped working".
I receive that error while the messagebox "Returned from thread" is displayed.
This means no code afterwards the messagebox has been executed.

Anders Branderud
http://bloganders.blogspot.com
0
itsmeandnobodyelseCommented:
Try the below code:


DWORD WINAPI ThreadProc(void * lpParameter) 
{ 
   OutputDebugString(L"Start ThreadProc");       
  
   // Some IO for th euser 
   if (failed_to_delete_file_ending_int >= 0 && failed_to_delete_file_ending_int <= 9 )
   {
      std::wstring wavfile = L"ljudfiler/output0.wav";
      wavfile[wavfile.find(L'0')] += (char)failed_to_delete_file_ending_int; 
      PlaySound ( wavfile.c_str(), NULL,SND_SYNC); 
      audio_file_is_playing =false; //loop will terminate in gui thread.. 
          
  
       OutputDebugString(L"Thread stopped..", L"inside of thread task...."); 
       return 0; 
    }
} 
 
//From function in GUI: 
 
 //CREATE THREAD. 
 
 if (error_nr_of_times == 0 ) 
 { 
     hThread = CreateThread (0,0,(LPTHREAD_START_ROUTINE) ThreadProc(NULL), 0,0 ,0);    
            
     while (hThread == 0 ) 
                                           { 
     if (hThread == 0) // error . 
        return;  
 }                                 }

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
AndersBranderudAuthor Commented:
Sorry for my late reply and thanks for your reply!
I have unfortunatley no time to test if the solution works. I reward the solution with points assuming it is correct. If somebody wants to control it is correct they are free to do so.

Anders Branderud
http://bloganders.blogspot.com
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.