C++ - _beginthreadex() 不启动线程

C++ - _beginthreadex() doesn't start the thread

本文关键字:启动 线程 beginthreadex C++      更新时间:2023-10-16

我有点困惑,为什么_beginthreadex()不开始我的线程。基本上,我有一个线程:

EDIT #3—添加了while(),作为我代码的一部分,但我最初从未声明过,因此这个线程必须始终运行,直到它内部提示退出代码。它必须与我的实际应用程序一起运行(因此,我实际上不能WaitForSingleObject(HANDLE, INFINITE))

unsigned int WINAPI MyThread1(LPVOID)
{  
     MessageBoxA(0, "We're in!", 0, 0);
     while (TRUE)
     {
          // do something
     }
}
我有我的_beginthreadex()代码:
/*
   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
}

这个文件是一个DLL扩展名。

为什么线程从来没有运行过,换句话说,为什么当_beginthreadex()通过时,我从来没有看到MessageBoxA()出现在我的屏幕上?是不可能在DLL文件中使用_beginthreadex(),还是什么?

编辑# 1

我已经实现了Richard Chambers在他的回复中所说的。

我从GetExitCodeThread()中得到错误码,并将其输出到MessageBoxA()中,错误码输出为259

查看MSDN系统错误代码列表后:这里

错误码对应如下:

ERROR_NO_MORE_ITEMS
259 (0x103)
No more data is available.

编辑# 2

我在这里阅读,我注意到这个文本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.——这可能与我的问题有任何关系吗?如果是这样,the thread is still running是什么意思?如果它已经在运行,那么为什么我不能在我的MessageBox中看到它的任何输出,或者它的其余内容?

那么,有了这些结论,我该怎么办呢?如何解决这个问题?

下面是在Visual Studio 2012中作为控制台应用程序编译和运行的两个简单示例。创建一个简单的Windows控制台应用程序,然后将此源代码粘贴到文件中。没有太多的错误检测方式,但主要部分的工作。

_beginthreadex()在Windows API中为CreateThread()提供了一个包装器,但是文档表明它在启动线程时为C/c++运行时进行必要的初始化。请参阅Windows threading: _beginthread vs _beginthreadx vs CreateThread c++,详细了解在Windows中启动线程的这三种方式之间的差异。

在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;
}

使用标准的Add向导将一个简单的控制台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代码中,并且在主程序调用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