【问题标题】:C++ win32 thread createThread function not passing parameter correctlyC++ win32线程createThread函数未正确传递参数
【发布时间】:2015-12-16 23:51:04
【问题描述】:

所以,我一直在试图弄清楚 c++ 多线程是如何工作的,以及如何将它应用到我正在从事的项目中。我正在尝试完成创建一个新线程并在该线程上运行一个函数。我尝试运行的函数称为SetupInfo,并将Individual 作为单个参数。我已经看到了这样的示例并尝试实现它们,但是经过多次尝试后,我无法成功地将所需的参数传递到我希望函数在其上运行的线程中。这是我想出的:

在这里我创建了一个结构来存储指向Individual 的指针,我稍后需要它。

struct ThreadData
{
 Individual *m_pInd;
 ThreadData(Individual pInd) : m_pInd(*pInd) {}
};

在这里,我创建了一个可以在程序中调用的函数,该函数创建了运行函数 SetupThreadFunction 的线程,该函数将 void 指针作为参数。我正在尝试将变量 data 传递给此函数,然后将其转换回 ThreadData 以便能够访问结构的项目。

void SetupThread(Individual input)
{
   ThreadData *data = new ThreadData(input);
   CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SetupThreadFunction, data , 0, 0);
   delete data;
}

在这里,我创建了传递给CreateThread 函数的函数,该函数接受一个空指针并将其转换为ThreadData,然后理论上可以访问threadData->m_pInd。上面data 的相同指针被正确传递到SetupThreadFunction。但是,m_pInd 包含空数据,而不是指向预期信息的指针。 为什么会这样?

DWORD WINAPI SetupThreadFunction(LPVOID lpParameter)
{
 ThreadData* threadData = (ThreadData*)lpParameter;
 SetupInfo(threadData->m_pInd);
 return 0;
}

有没有更正确的方法将参数传递到我正在创建的新 win32 线程中?

【问题讨论】:

  • 所以,我一直在试图弄清楚 c++ 多线程是如何工作的——我不明白你发布的第一个 struct 应该如何工作,线程或没有线程。你取临时参数的地址?
  • 第一个问题,你不应该删除SetupThread中的data。在SetupThreadFunction 中使用后应将其删除。否则,您已经设置了一个悬空指针。请记住,CreateThreadSetupThreadFunction 完成执行之前返回(可能在它开始执行之前)。
  • 另外,当线程可能仍在运行时,为什么要删除数据?多线程不仅仅是调用CreateThread。您需要适当的同步,也可能需要“等待”线程完成执行,然后再插入数据。
  • @fudge22it Individual 到底是什么?
  • SetupThread 按值获取参数。这意味着当SetupThread 被调用时,作为input 传递的任何内容都会被复制,并且在函数返回时它不再存在。如果你取input的地址,你取的是临时地址(我没看到你实际上取了地址)。您必须确保它的生命周期至少与 SetupThreadFunction 完成执行时一样

标签: c++ multithreading pointers winapi


【解决方案1】:

正确的模式是用new分配对象,填入数据(如果没有通过参数给new做),将指针传递给新创建的线程,让线程delete对象完成后。你delete对象在你知道线程已经开始之前!

【讨论】:

    【解决方案2】:

    这不是多线程问题;这是一个指针问题。

    这行对我来说没有意义:

    ThreadData(Individual pInd) : m_pInd(*pInd) {}
    

    m_pInd 是一个指针,但你用*pInd 初始化它,这意味着你想取消引用pInd,但pInd 不是指针,更不用说指向指针的指针了。我什至不知道这将如何编译。

    假设您实际上是指 & 而不是 *,如下所示:

    ThreadData(Individual ind) : m_pInd(&ind) {}
    

    这里的问题是,您正在堆栈上创建一个指向 Individual 副本的指针,并且该副本在从构造函数返回时消失,因此您有一个悬空指针。

    【讨论】:

      【解决方案3】:

      使用std::thread

      void ThreadProc(Individual individual);
      
      int main()
      {
          Individual individual;
          std::thread thread(ThreadProc, individual);
          thread.join();
          return 0;
      }
      

      【讨论】:

      • std:thread 是否与 Visual Studios 2008 一起编译?代码尚未更新以适用于较新版本的视觉工作室,不幸的是限制了我可以使用的工具。
      • @fudge22it: std::thread 在 Visual Studio 2012 中引入。
      • 只有在Individual 是可复制的情况下才能解决问题。如果不是,那么它会遇到大致相同的问题(或至少一个相同的问题)。
      • @AdrianMcCarthy:但在这种情况下,搬家仍然是一种选择。
      • @MSalters:由于 fudge22it 没有向我们展示任何有关个人的信息,即使在 cmets 中被要求提供它之后,我也不太相信它是可移动的或可复制的。
      【解决方案4】:

      这里有一个简单的代码示例来演示已经讨论过的要点。

      #include "stdafx.h" // includes <windows.h>, <string> and <iostream>
      
      using std::string;
      using std::cout;
      
      class Individual
      {
      public:
          string s;
      };
      
      struct ThreadData
      {
          Individual *m_pInd;
          ThreadData(Individual* pInd) : m_pInd(pInd) {}
      };
      
      DWORD WINAPI SetupThreadFunction(LPVOID lpParameter)
      {
          cout << "Hi From Thread\n";
          ThreadData* threadData = static_cast<ThreadData*>(lpParameter);
          //SetupInfo(threadData->m_pInd);
      
          // do delete here, once its finished with.
          delete threadData;
          return 0;
      }
      
      HANDLE SetupThread(Individual* input)
      {
          ThreadData *data = new ThreadData(input);
          return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SetupThreadFunction, data , 0, 0);   
      }
      
      int _tmain(int argc, _TCHAR* argv[])
      {
          cout << "Hi\n";
          Individual* i = new Individual;
      
          HANDLE h = SetupThread(i);
      
          if(h)   
          {
              WaitForSingleObject(h, INFINITE);
              cout << "Done\n";
          } else
          {
              cout << "Couldnt create thread\n";
          }   
      
          getchar();
      
          delete i;
      
          return 0;
      }
      

      请记住,您还可以使用_beginthread 作为更简单的界面来在 Win32 上启动线程。

      【讨论】:

        猜你喜欢
        • 2022-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-13
        • 1970-01-01
        • 2016-10-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多