因此,我正在尝试制作一个简单的多线程程序来验证 Collatz 猜想的大量数字并返回已验证数字的总数。每个线程(总共 4 个)执行一个数字间隔,并在数字达到 1 时更新“已验证”变量。我还对整个过程进行计时(与单线程计算进行比较)
我遇到的问题是,当我在程序末尾打印出“已验证”int 时,从来没有任何一致性,所以我猜测要么是线程正在相互覆盖,要么是主线程在其他人之前完成,因此打印不完整的数字。我还假设 clock() 计算也将关闭,如果主线程在其他线程之前完成的话。那么,如何阻止主线程继续运行直到其他线程完成(从而使其等待更新的验证计数并完成准确的时间测量)?这就是我认为 WaitForSingleObject 所做的,但我猜它只是停止了主线程退出,仍然允许它计算它的其他函数。
这是我第一次接触多线程,我认为我不太了解同步的工作原理和 WaitForSingleObject 命令。到目前为止,这是我的主要功能:
编辑:这是我更新的 Main 函数和 Collatz 函数。我对其进行了修改,以便每个线程都访问一个单独的变量以避免同步问题,但问题仍然存在。当我打印出“validated”时没有一致的值 *
再次编辑:好吧,所以我根据 Mladen Janković 删除了“线程”int,并且只使用了一个简单的计数器来将不同的时间间隔分配给创建的线程。 “已验证”现在有一个一致、正确的值。但是,当有 1,000,000 个数字时,我仍然无法让程序真正完成。对其进行 100,000 甚至 10,000 的测试都可以完美运行,但是当我将其增加到 1,000,000 个数字时,程序会无限期地(小时)运行而不会实际返回值。我猜它会卡在一个特定的值上(例如 Martin James 指出的 750831)。我尝试用 int 替换 long int,但它似乎仍然存在溢出问题。有什么建议么?并感谢您提供的巨大帮助。
最后编辑:好的,所以我只是使用 long long 而不是 int,现在程序可以完美运行。感谢大家的帮助!
void main()
{
clock_t start;
clock_t finish;
unsigned int thread = 0;
start = clock();
HANDLE h1 = (HANDLE)_beginthreadex(NULL, 0, collatz_thread, NULL, 0, NULL);
HANDLE h2 = (HANDLE)_beginthreadex(NULL, 0, collatz_thread, NULL, 0, NULL);
HANDLE h3 = (HANDLE)_beginthreadex(NULL, 0, collatz_thread, NULL, 0, NULL);
for (int i = 750001 ; i <= 1000000 ; i++) { collatz(i, 4); }
WaitForSingleObject( h1, INFINITE );
WaitForSingleObject( h2, INFINITE );
WaitForSingleObject( h3, INFINITE );
finish = clock() - start;
double time = finish / (double) CLOCKS_PER_SEC;
validated = v1 + v2 + v3 + v4;
cout << validated << " numbers validated." << endl;
cout << endl << time << " seconds." << endl;
}
unsigned _stdcall collatz_thread (void* n)
{
selection++; // selects a different interval each time collatz_thread is called
switch (selection) {
case 1:
for (int i = 1 ; i <= 250000; i++) { collatz(i, 1); }
break;
case 2:
for (int i = 250001 ; i <= 500000; i++) { collatz(i, 2); }
break;
case 3:
for (int i = 500001 ; i <= 750000; i++) { collatz(i, 3); }
break;
}
return 0;
}
int collatz (int n, int thread)
{
int original = n;
while (n != 1) {
if (n%2 == 0)
n = (n/2);
else
n = (3*n + 1);
}
if (n == 1) {
switch (thread) {
case 1:
v1++;
break;
case 2:
v2++;
break;
case 3:
v3++;
break;
case 4:
v4++;
break;
}
return n;
}
最佳答案
如果是共享变量,你需要同步访问validated
。最简单的方法是使用 InterlockedIncrement
函数而不是标准的 ++
操作符来增加它。另一种方法是在访问共享变量时使用某种同步对象,如自旋锁或互斥锁,但如果您只需要同步增量操作,那就太过分了。
如果您需要更多详细信息,请提供collatz
函数的代码。
正如“usr”所建议的那样,为了获得更好的性能,您可以为每个线程使用单独的变量,然后在主线程中对它们求和。在这种情况下,您应该以这种方式填充这些变量,使它们不共享相同的缓存行以避免 false sharing .
您还没有提供 collatz_thread
函数,这可能是导致结果不一致的另一个原因。原因是您将指针传递给存储线程#的变量(&thread
),线程#在创建新线程的调用之间发生变化,因此根据操作系统调度程序的状态,新当 thread
变量已更改为具有另一个值时,线程可能没有机会启动,因此您将有多个线程执行同一组数据,而其他组可能会被跳过。由于行为取决于线程调度程序的当前状态,因此它几乎不可预测。
解决方案是将 thread
变量转换为 void*
而不是传递其地址,然后在 collatz_thread
函数中将其转换回 整数
:
HANDLE h1 = (HANDLE)_beginthreadex(NULL, 0, collatz_thread, (void*)thread, 0, NULL);
正如 Martin 所建议的,您可能会遇到整数溢出,但它不应该导致不一致的结果,只是错误的结果,但仍然是一致的。
关于c++ - 简单的多线程帮助? C++、WaitForSingleObject 和同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10164469/