Reputation: 53
I'm a little confused here as to why _beginthreadex()
doesn't start my thread. Basically, I have a thread:
EDIT #3 -- Added the while(), as its part of my code, but I never stated that initially, therefore this thread has to always run until an exit code is prompted inside of it. And it has to run alongside my actual application (therefore, I cannot actually WaitForSingleObject(HANDLE, INFINITE)
)
unsigned int WINAPI MyThread1(LPVOID)
{
MessageBoxA(0, "We're in!", 0, 0);
while (TRUE)
{
// do something
}
}
And I have my _beginthreadex()
code:
/*
take note that, this is inside another function, and that function is also
called through a seperate _beginthreadex() call, so basically, this thread
is supposed to be called from within another thread
*/
if (user.settingsPage.ChangeVolume > 0)
{
_beginthreadex(0, 0, &MyThread1, 0, 0, 0);
// do some cleanup here, of non-related things
}
This file is a DLL extension.
Why doesn't the thread ever run, in other words, why don't I ever see the MessageBoxA()
appear on my screen when _beginthreadex()
is passed? Is it not possible use _beginthreadex()
in a DLL file, or what?
EDIT #1
I've implemented what Richard Chambers
said in his reply.
I got the error code from GetExitCodeThread()
, and outputted it in a MessageBoxA()
, the error code output was 259
.
After looking at the MSDN system error codes list: here
The error code corresponds to the following:
ERROR_NO_MORE_ITEMS
259 (0x103)
No more data is available.
EDIT #2
I was reading here, and I noticed this text If a thread returns STILL_ACTIVE (259) as an error code, applications that test for this value could interpret it to mean that the thread is still running and continue to test for the completion of the thread after the thread has terminated, which could put the application into an infinite loop.
-- Could this have anything to do with my issue? And if so, what does it mean by the thread is still running
? If it's already running, then how come I can't see any output from it in my MessageBox, or the rest of its content?
So, provided those conclusions, what am I to do? How can I solve this issue?
Upvotes: 3
Views: 4339
Reputation: 17573
Here are two simple examples that compile and run in Visual Studio 2012 as a console application. Create a simple Windows console application and then paste this source code into the file. There is not much in the way of error detection however the main parts work.
_beginthreadex()
provides a wrapper for CreateThread()
in the Windows API however the documentation indicates that it does the necessary initiation for the C/C++ run time as part of starting up the thread. See Windows threading: _beginthread vs _beginthreadex vs CreateThread C++ for details about the differences between these three ways of starting a thread in Windows.
Starting a thread is used in DLLs and COM objects all the time so there is something else that is wrong. The following example starts up a thread at a time.
// threadtest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
// necessary include files for a Console application wanting to do some Windows things with threads.
// ordinarily #include <Windows.h> would be added to stdafx.h for this Console application.
// Windows.h provides things such as the Sleep() function as well as definitions for HANDLE, etc.
// process.h provides the prototypes and declarations for _beginthreadex()
// iostream with no .h provides the C++ Standard Library I/O routines for std::cout
#include <Windows.h>
#include <process.h>
#include <iostream>
// list of arguments to provide to the thread being started up.
struct argList {
int i1;
int i2;
int i3;
};
unsigned int WINAPI myThread (void * args)
{
argList *pArgs = (argList *)args; // convert the LPVOID to the proper type to access the arguments.
// a bit of output to let us know we got here then a sleep to slow things down a touch.
std::cout << "myThread is running? args " << pArgs->i1 << ", " << pArgs->i2 << ", " << pArgs->i3 << std::endl;
Sleep(1000);
// add the arguments and return the sum.
return (pArgs->i1 + pArgs->i2 + pArgs->i3);
}
// declare the function in the DLL we are going to call.
__declspec(dllimport) HANDLE __cdecl Function1(void);
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hThread;
DWORD exitCode;
argList myArgs = {1, 2, 3};
std::cout << "main is running?" << std::endl;
// start a thread with the arguments we want to sum and wait for it to complete and return to us.
// when it returns we will fetch the return value which is the sum of the arguments.
hThread = (HANDLE)_beginthreadex (0, 0, myThread, &myArgs, 0, 0);
WaitForSingleObject (hThread, INFINITE); // Wait for the thread we started to complete, a kind of Join
GetExitCodeThread (hThread, &exitCode); // Get the thread's exit code so that we can print it out
CloseHandle (hThread); // We be done with the thread so close out it's handle to release resources
std::cout << "main ending, thread exit code " << exitCode << std::endl;
// now call the function in our DLL which will start up a thread there
// get its handle so that we can check the exit code, etc.
hThread = Function1();
WaitForSingleObject (hThread, INFINITE); // Wait for the thread we started to complete, a kind of Join
GetExitCodeThread (hThread, &exitCode); // Get the thread's exit code so that we can print it out
CloseHandle (hThread); // We be done with the thread so close out it's handle to release resources
std::cout << "main ending, Function1 exit code " << exitCode << std::endl;
return 0;
}
A simple console DLL project was added to the Visual Studio 2012 solution using the standard Add wizard. I modified what was an empty file, not the DLL main file containing the DLL message handlers for attach, etc. The modified file contains the following:
#include "stdafx.h"
#include <Windows.h>
#include <process.h>
#include <iostream>
unsigned int WINAPI myThread2 (void * args)
{
// a bit of output to let us know we got here then a sleep to slow things down a touch.
std::cout << "myThread2 is running? args " << std::endl;
MessageBox (0, L"A message2 text", L"Caption 2", 0);
Sleep(1000);
// add the arguments and return the sum.
return 345;
}
__declspec(dllexport) HANDLE __cdecl Function1(void)
{
std::cout << " in DLL, starting thread." << std::endl;
HANDLE hThread = (HANDLE)_beginthreadex (0, 0, myThread2, 0, 0, 0);
return hThread;
}
Multiple Threads
If the simple application is modified to have loops in the threads with output we could have several simultaneous threads running. The main could be modified to look like the following where we start two different threads which we are interested in managing and then wait for both to finish then check the exit status of both threads as follows. There is a third thread which is started however we do not both to get its handle nor manage it. It runs a short time then ends.
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hThreads[2];
DWORD exitCode;
unsigned int threadId;
argList myArgs = {1, 2, 3};
std::cout << "main is running?" << std::endl;
// start a thread with the arguments we want to sum and wait for it to complete and return to us.
// when it returns we will fetch the return value which is the sum of the arguments.
hThreads[0] = (HANDLE)_beginthreadex (0, 0, myThread, &myArgs, 0, &threadId);
hThreads[1] = Function1();
WaitForMultipleObjects (2, hThreads, TRUE, INFINITE); // Wait for all threads we started to complete, a kind of Join
GetExitCodeThread (hThreads[0], &exitCode); // Get the thread's exit code so that we can print it out
std::cout << "main ending, thread 1 exit code " << exitCode << std::endl;
GetExitCodeThread (hThreads[1], &exitCode); // Get the thread's exit code so that we can print it out
std::cout << "main ending, thread 2 exit code " << exitCode << std::endl;
CloseHandle (hThreads[0]); // We be done with the thread so close out it's handle to release resources
CloseHandle (hThreads[1]); // We be done with the thread so close out it's handle to release resources
return 0;
}
Each of the three threads has a simple loop which counts up to a final value and displays a message to standard output. A Sleep(1000)
gives us a way to slow down everything. So each thread has a loop that looks like the following which is from thread number 3.
MessageBox (0, L"A message 3 text", L"Caption 3", 0);
std::cout << " myThread 3 after MessageBox - start loop" << std::endl;
for (int i = 0; i < 10; i++) {
Sleep(1000);
std::cout << " myThread 3 is running step "<< i << std::endl;
}
std::cout << "myThread 3 end" << std::endl;
The DLL source for this example starts a thread in the exported entry point Function1()
and the thread started in Function1()
starts a third thread.
#include "stdafx.h"
#include <Windows.h>
#include <process.h>
#include <iostream>
unsigned int WINAPI myThread3 (void * args)
{
// a bit of output to let us know we got here then a sleep to slow things down a touch.
std::cout << "myThread3 is running? args " << std::endl;
MessageBox (0, L"A message 3 text", L"Caption 3", 0);
std::cout << " myThread 3 after MessageBox - start loop" << std::endl;
for (int i = 0; i < 10; i++) {
Sleep(1000);
std::cout << " myThread 3 is running step "<< i << std::endl;
}
std::cout << "myThread 3 end" << std::endl;
return 2356;
}
unsigned int WINAPI myThread2 (void * args)
{
// a bit of output to let us know we got here then a sleep to slow things down a touch.
std::cout << "myThread2 is running? args " << std::endl;
MessageBox (0, L"A message 2 text", L"Caption 2", 0);
std::cout << " myThread 2 after MessageBox - start myThread3 then loop" << std::endl;
HANDLE hThread = (HANDLE)_beginthreadex (0, 0, myThread3, 0, 0, 0);
for (int i = 0; i < 10; i++) {
Sleep(1000);
std::cout << " myThread 2 is running "<< i << std::endl;
}
std::cout << "myThread 2 end" << std::endl;
// add the arguments and return the sum.
return 345;
}
__declspec(dllexport) HANDLE __cdecl Function1(void)
{
std::cout << " in DLL, starting myThread 2." << std::endl;
HANDLE hThread = (HANDLE)_beginthreadex (0, 0, myThread2, 0, 0, 0);
return hThread;
}
The output shows all the various threads running with the count up. Notice in the output that thread 3, which was started by thread 2 continues running after thread 2 ends due to the delay of starting its loop. Both thread 2 and thread 3 are in the DLL code and are started when the main calls the DLL entry point of Function1()
.
main is running?
in DLL, starting myThread 2.
myThread is running? args myThread2 is running? args 1, 2, 3
myThread after MessageBox - start loop
myThread is running i = 0
myThread is running i = 1
myThread 2 after MessageBox - start myThread3 then loop
myThread3 is running? args
myThread is running i = 2
myThread 2 is running 0
myThread is running i = 3
myThread 2 is running 1
myThread is running i = 4
myThread 3 after MessageBox - start loop
myThread 2 is running 2
myThread is running i = 5
myThread 3 is running step 0
myThread 2 is running 3
myThread is running i = 6
myThread 3 is running step 1
myThread 2 is running 4
myThread is running i = 7
myThread 3 is running step 2
myThread 2 is running 5
myThread is running i = 8
myThread 3 is running step 3
myThread 2 is running 6
myThread is running i = 9
myThread 3 is running step 4
myThread 2 is running 7
myThread is running i = 10
myThread 3 is running step 5
myThread 2 is running 8
myThread is running i = 11
myThread 3 is running step 6
myThread 2 is running 9
myThread 2 end
myThread is running i = 12
myThread 3 is running step 7
myThread is running i = 13
myThread 3 is running step 8
myThread is running i = 14
myThread 3 is running step 9
myThread 3 end
myThread is running i = 15
myThread is running i = 16
myThread is running i = 17
myThread is running i = 18
myThread is running i = 19
myThread end
main ending, thread 1 exit code 6
main ending, thread 2 exit code 345
Upvotes: 3