以下是在 Visual Studio 2012 中作为控制台应用程序编译和运行的两个简单示例。创建一个简单的 Windows 控制台应用程序,然后将此源代码粘贴到文件中。错误检测的方式不多,但主要部分工作。
_beginthreadex() 在 Windows API 中为 CreateThread() 提供了一个包装器,但是文档表明它为 C/C++ 运行时进行了必要的初始化,作为启动线程的一部分。有关这三种在 Windows 中启动线程的方式之间的区别的详细信息,请参阅Windows threading: _beginthread vs _beginthreadex vs CreateThread C++。
在 DLL 和 COM 对象中一直使用启动线程,因此存在其他问题。以下示例一次启动一个线程。
// 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;
}
使用标准添加向导将一个简单的控制台 DLL 项目添加到 Visual Studio 2012 解决方案中。我修改了一个空文件,而不是包含用于附加的 DLL 消息处理程序等的 DLL 主文件。修改后的文件包含以下内容:
#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;
}
多线程
如果简单的应用程序被修改为在带有输出的线程中有循环,我们可以同时运行多个线程。可以将 main 修改为如下所示,我们启动两个我们有兴趣管理的不同线程,然后等待两者完成,然后检查两个线程的退出状态,如下所示。有第三个线程已启动,但我们既不能获取它的句柄,也不能管理它。它会运行一小段时间然后结束。
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;
}
三个线程中的每一个都有一个简单的循环,该循环计数到一个最终值并在标准输出中显示一条消息。 Sleep(1000) 为我们提供了一种减慢速度的方法。所以每个线程都有一个循环,如下所示,来自线程号 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;
此示例的 DLL 源在导出的入口点 Function1() 中启动一个线程,在 Function1() 中启动的线程启动第三个线程。
#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;
}
输出显示所有不同的线程在计数时运行。请注意,在输出中,由线程 2 启动的线程 3 在线程 2 结束后由于启动其循环的延迟而继续运行。线程2和线程3都在DLL代码中,在main调用Function1()的DLL入口点时启动。
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