使用_beginthreadx将结构传递给线程

时间:2012-01-13 15:32:44

标签: c++ multithreading data-structures

#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.

我知道我必须通过值传递输入而不是引用但是它一直给我一个错误信息,这是什么方法呢?

4 个答案:

答案 0 :(得分:1)

您为每个帖子提供相同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,以便它们不会尝试从同一个内存地址读取。这样,没有竞争条件。该术语指的是线程启动和执行顺序无法保证,因此如果线程在没有同步的情况下访问相同的资源,它们将“竞争”。

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

当你为每个线程覆盖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;
}

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

答案 3 :(得分:0)

第一点是:

对于正在传递给多个线程的数据结构,没有适当的同步,虽然这些线程正在对它做一些事情,但您已经完成了循环的下一次迭代并且正在更改数据结构的价值。

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