使用 _beginthreadx 将结构传递给线程

Passing structure to thread using _beginthreadx

本文关键字:线程 结构 beginthreadx 使用      更新时间:2023-10-16
#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <windows.h>
#include <process.h>
using namespace std;
HANDLE ghEvents;

struct DataStructure
{
int r[2];
int h;
};

unsigned __stdcall f2(void *p)
{
DataStructure *input = (DataStructure *)p;
int i = (int)input->h;
cout <<i<<endl;
}   

int main()
{
HANDLE hThread[8];
DWORD i, dwEvent, dwThreadID;
unsigned threadID;
DataStructure input;
ghEvents = CreateEvent(NULL,FALSE,FALSE,NULL);  
for (int i = 0; i < 8; i++) 
{   
input.h=i;
hThread[i] = (HANDLE)_beginthreadex( NULL, 0, f2, (void*)&input, 0, &threadID );
}
dwEvent = WaitForMultipleObjects(8,hThread,TRUE,INFINITE);       
CloseHandle(ghEvents); 
for (int i = 0; i < 8; i++) 
{
CloseHandle( hThread[i] );
}
cin.get();
return 0;
}

输出是77777777而不是12345678。

我知道我必须通过值而不是引用传递输入,但它一直给我一条错误消息,正确的方法是什么?

这是我之前的回答之后,如果在编译时知道线程数,这是一个更好的解决方案。

DataStructure input[8];  
... 
for (int i = 0; i < 8; i++)   
{     
   input[i].h=i;  
   hThread[i] = (HANDLE)_beginthreadex( NULL, 0, f2, (void*)&input[i], 0, &threadID );  
} 

并且您需要返回一个值:

unsigned __stdcall f2(void *p)      
{      
   DataStructure *input = (DataStructure *)p;      
   int i = input->h;      
   cout <<i<<endl;      
   return 0; 
} 

您为每个线程提供了相同DataStructure的地址。您的输出是不确定的。根据每个线程何时运行,它们可能会在该循环的另一次迭代之前、期间或之后读取。这意味着,当线程启动并访问input->h时,主线程可能已经继续并更改input.h到下一次迭代。

例:

  • Main - 循环迭代 0 将input.h设置为 0。
  • Main - 循环迭代 0 以 input 作为参数启动线程 0。
  • Main - 循环迭代 1 将 input.h 设置为 1。
  • Main - 循环迭代 1 以 input 作为参数启动线程 1。
  • Main - 循环迭代 2 将 input.h 设置为 2。
  • Main - 循环迭代 2 以 input 作为参数启动线程 2。
  • 线程 1 - 启动。
  • 线程 0 - 启动。
  • Main - 循环迭代 3 将 input.h 设置为 3。
  • 线程 0 - 读取input->h为 3。
  • 线程 2 - 启动。
  • Main - 循环迭代 3 以 input 作为参数启动线程 3。
  • 线程 1 - 读取input->h为 3。
  • 线程 3 - 启动。
  • Main - 循环迭代 4 将 input.h 设置为 4。
  • 线程 3 - 读取input->h为 4。
  • 线程 2 - 读取input->h为 4。
  • 线程 4 - 启动。
  • 线程 4 - 读取input->h为 4。

最终输出:3344

为每个线程提供不同的DataStructure,以便它们不会尝试从相同的内存地址读取。这样,就没有竞争条件。该术语是指线程启动和执行顺序无法保证的事实,因此如果线程在没有进行同步的情况下访问相同的资源,它们将"竞争"。

第一点是:

对于传递给多个线程的数据结构,您没有同步,当这些线程对其进行某些操作时,您已经在经历循环的下一次迭代并更改数据结构的值。

在循环中创建新的数据结构以避免出现同步问题。

您需要为每个线程创建数据结构,因为要覆盖每个线程的input.h值。

因此,要修复,请将其更改为

DataStructure *input; 
...
for (int i = 0; i < 8; i++)  
{    
   input = new DataStructure ;
   input->h=i; 
   hThread[i] = (HANDLE)_beginthreadex( NULL, 0, f2, (void*)input, 0, &threadID ); 
}

为了避免内存泄漏,请获取 f2 函数以删除输入,即

unsigned __stdcall f2(void *p)     
{     
   DataStructure *input = (DataStructure *)p;     
   int i = input->h;     
   cout <<i<<endl;     
   delete input;
   return 0;
}

注意 此解决方案使用动态内存分配,如果编译时线程数未知,则此解决方案是很好的解决方案。如果线程数已知,请参阅我的另一个答案。