4

我正在学习线程,我发现了一些简单的例子。

我希望做的是创建 5 个线程,每个线程分配一个随机数给 20 个 int 的数组。然后最后有另外 5 个线程将这个数组重建为一个更大的 100 大小的 int。

这是我尝试过的一些先前的代码。我希望能够通过引用传递一个数组,但没有运气。

任何想法将不胜感激,请记住,我对线程完全陌生

#include <process.h>
#include <windows.h>
#include <iostream>
#include <fstream>
#include <time.h>
//#include <thread>

using namespace std;

void myThread (void *dummy );
void myThread2 (void *dummy );

int main()
{

    ofstream myfile;
    myfile.open ("coinToss.csv");

    int rNum;

    long numRuns;
    long count = 0;
    int divisor = 1;
    float holder = 0;
    int counter = 0;
    float percent = 0.0;

    int array1[1000000];
    int array2[1000000];


    srand ( time(NULL) );

    printf ("Runs (use multiple of 10)? ");
    cin >> numRuns;

    for (int i = 0; i < numRuns; i++)
    {
        _beginthread( myThread, 0, (void *) (array1) );
        _beginthread( myThread2, 0, (void *) (array2) );

    }

}

void myThread (void *param )
{
    int i = *(int *)param;

    for (int x = 0; x < 1000000; x++)
    {
        //param[x] = rand() % 2 + 1;
        i[x] = rand() % 2 + 1;
    }

}

void myThread2 (void *param )
{
    int i[1000000] = *(int *)param;

    for (int = 0; x < 1000000; x++)
    {
        i[x] = rand() % 2 + 1;
    }

}
4

3 回答 3

5

首先你需要意识到:

 for (int i = 0; i < numRuns; i++)
    {
        _beginthread( myThread, 0, (void *) (array1) );
        _beginthread( myThread2, 0, (void *) (array2) );

    }

来电立即_beginthread返回。他们不等待线程完成,甚至开始。它只是将操作系统调度程序中的线程排队并返回。

但是,上面的代码是main()函数的结尾。我非常怀疑在发布版本下,您的线程甚至会在整个程序退出之前初始化。您需要构建一种机制,通过该机制,您的主线程将在程序关闭之前等待工作线程完成它们的工作。这样做超出了 SO 帖子的范围,但请查看CreateEvent()WaitForMultipleObjects()

接下来你需要了解的是你发送给线程的东西的生命周期和所有权语义。您正在传递指向数组的指针,这些数组是范围内的自动变量main()

 int array1[1000000];
 int array2[1000000];

一旦声明这些数组的范围(此处为main())退出,变量就不再存在。将指向局部作用域变量的指针传递给工作线程很少是正确的——如果局部作用域在线程完成之前退出,则永远不会正确。

动态分配这些数组,然后将它们的所有权转移给工作线程将在这里解决这个问题。执行此操作时,请在管理这些对象/数组的所有权语义时小心。

于 2012-10-09T14:16:20.847 回答
3

1、铸造:

注意选角!

void myThread (void *param )
{
  int *i = (int *) param;
  for (int x = 0; x < 1000000; x++)
  {
    i[x] = rand() % 2 + 1;
  }
}

二、适用范围:

两个线程都是开始numRuns时间。启动它们需要一些时间。也执行它们。不应该在不尊重线程的情况下结束。main您应该通过WaitForMultipleObjects监视线程。_beginthread() 返回一个waitable handle.

实施:

int main()
{
  long numRuns;
  HANDLE hThread[MAX_WAIT_OBJECTS];

  cin >> numRuns;
  // numRuns to be smaller than MAX_WAIT_OBJECTS/2!!!!


  for (int i = 0; i < numRuns; i++)
  {
     hThread[i * 2]     = _beginthread( myThread, 0, (void *) (array1) );
     hThread[i * 2 + 1] = _beginthread( myThread2, 0, (void *) (array2) );
     // or better use _beginthreadex(...)
  }
  WaitForMultipleObjects(numRuns * 2, hThread, TRUE, INFINITE);
  // bWaitAll flag set TRUE causes this statement to wait until all threads have finished.
  // dwMilliseconds set to INFINITE will force the wait to not timeout.
}

这样,main只有在所有线程都完成工作后才会完成。

3.访问:

这两个数组都在该main部分中声明,因此线程共享它们。为了保护访问,您应该引入某种排他性。最简单的是临界区对象。当所有线程 2 只访问数组 2 并且所有线程 1 只访问数组 1 时,我建议使用 2 个临界区对象。一个临界区一次只能被一个线程访问。

执行:

CRITICAL_SECTION cs1,cs2; // global

int main()
{
  long numRuns;
  HANDLE hThread[1000];

  // critical section object need to be initialized before aquired
  InitializeCriticalSection(&cs1);
  InitializeCriticalSection(&cs2);

  cin >> numRuns;

  for (int i = 0; i < numRuns; i++)
  {
    hThread[i * 2]     = _beginthread( myThread, 0, (void *) (array1) );
    hThread[i * 2 + 1] = _beginthread( myThread2, 0, (void *) (array2) );
  }
  WaitForMultipleObjects(numRuns * 2, hThread, TRUE, INFINITE);
}

和线程(这里只显示一个):

void myThread1 (void *param )
{
  EnterCriticalSection(&cs1); //aquire the critical section object
  int *i = (int *) param;
  for (int x = 0; x < 1000000; x++)
  {
    i[x] = rand() % 2 + 1;
  }
  LeaveCriticalSection(&cs1); // release the critical section object
}

然而:整个故事还有点不清楚。您希望多个线程同时从头到尾填充同一个数组。这听起来很奇怪。使用此处描述的临界区对象,无论如何,线程将一个接一个地执行。你的目标到底是什么?

于 2012-10-09T15:02:45.570 回答
1

其他答案涵盖了要点:还有另一个问题通常是一个问题(至少在 LINUX 上:不确定 Windows)

int array1[1000000];
int array2[1000000];

将非常大的数组声明为局部变量存在溢出堆栈空间的危险,从而导致程序崩溃。

于 2012-10-10T07:18:25.320 回答