【问题标题】:C++ - _beginthreadex() doesn't start the threadC++ - _beginthreadex() 不启动线程
【发布时间】:2015-12-16 21:17:25
【问题描述】:

我有点困惑为什么_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系统错误代码列表后:here

错误码对应如下:

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

编辑#2

我正在阅读here,并注意到此文本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 中看不到它的任何输出,或者它的其余内容?

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

【问题讨论】:

  • _beginthreadex 的调用的上下文是什么?返回值是多少? (返回是有效的HANDLE,还是NULL
  • 如何得到_beginthreadex的返回值?我试过 GetLastError() 但它返回 0。我该如何检查?
  • 除了猜测之外,没有足够的信息来做更多的事情。
  • "On an error, _beginthreadex returns 0, and errno and _doserrno are set."。此外,GetLastError 仅在 2 件事为真时才有效: 1- 函数失败。 2- 被调用函数的文档说应该调用GetLastError
  • 我所读到的所有内容都是在 DLL 启动、附加等中执行任何操作都会引入一些实际问题。没有什么可以阻止一个线程启动另一个线程,它一直在发生。我刚刚将它添加到我的演示中,以便第二个线程开始第三个线程,它工作得很好。 MessageBox() 是模态的,这可能是您的问题的一部分。

标签: c++ multithreading visual-studio winapi


【解决方案1】:

以下是在 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

【讨论】:

  • GetExitCodeThread()。这就是我一直在寻找的,谢谢,我稍后会将结果发布给您。
  • 我已使用您的代码收到的错误代码编辑了我的帖子,非常感谢您,一旦我获得 15 名声望,我将支持答案 - 但我该如何解决手头的问题?
猜你喜欢
  • 1970-01-01
  • 2010-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多