【问题标题】:Unexpected results printing array of int pointers in C在 C 中打印 int 指针数组的意外结果
【发布时间】:2014-10-14 01:41:21
【问题描述】:

我有一个简单的 C 程序,它使用不同数量的 pthread 来查找前 N 个素数,并将发现为素数的候选添加到数组中。数组作为 arg 传递给每个线程,每个线程在临界区执行几乎所有代码。我对素数检查没有任何问题,并且在找到素数和 result_number 变量时将它们打印到屏幕上是有效的。但是,当找到 N 个素数并打印数组时,我发现(大约)每第二次执行程序时,一些(从 1 到 5 不等)早期素数数组元素(通常限于那些 似乎都可以正常工作。

此外,如果程序是用单线程执行的(即多个线程之间不共享数组以进行更新),则永远不会出现这种特殊性。

result_number, Candidate, N 都是全局变量。

void *primeNums(void *arg) {

    pthread_mutex_lock(&mutex);

    int *array = (int *) arg;
    int is_prime = 0;
    int j = 0;

    while (result_number <= N) {

        candidate++;
        is_prime = checkPrime(candidate);

        if (is_prime == 1) {
            array[result_number] = candidate;
            if (result_number == N) {
                while (j < N) {
                    printf("%d\n", array[j]);
                    j++;
                }
            }
            /* Test verification output; always accurate */
            printf("Result number: %d = %d\n", result_number, candidate);
            result_number++;
        }
    }
    pthread_mutex_unlock(&mutex);
}

我真的不相信其他 Q 涵盖了这一点,正如我所看到的那样(并且更愿意找到答案来写我自己的问题)。诚然,我可能没有正确搜索。

编辑:不需要的输出示例: -386877696 3 -395270400 32605 11 13 ...

从这里继续。

【问题讨论】:

  • 如果我错了,请随时纠正我,但我相信它们(很可能)是适用的,不是吗?
  • 为什么你的函数需要一个空指针?
  • 只是一个疯狂的猜测:您的互斥锁可能有问题。您所观察到的将与您的 几个 线程同时处于临界区一致(前几个素数的冲突概率要高得多,因为它们的计算速度更快) .我不明白你真正想要的是什么:几乎整个函数都受到互斥锁的保护,所以(如果它有效),进入临界区的第一个线程将完成所有工作。然后它释放互斥体,然后其他线程就没有什么可做的了……
  • 除了互斥锁和初始化之外,唯一的事情是另一个线程可能会弄乱您的数组。其他地方发生了一些非常奇怪的事情。
  • 如果有一个完整的工作示例来显示未定义的行为,那就太好了。您还应该检查candidateresult_number 等的初始化...

标签: c arrays multithreading


【解决方案1】:

我有一种预感,如果不是传入数组并使用全局 result_number,而是传入数组 + result_number 并在局部变量上循环:i = 0; while(i &lt; N) {...},你可能会解决你的问题。 (假设array + result_number + N - 1 没有越界)。

使用全局变量来保存每个线程的范围信息的问题是线程函数primeNums() 修改了其中的一些。因此,如果您启动第一个线程(线程#1)并将result_number 设置为您希望线程#1 处理的范围的开始,则线程#1 将在您将其重置为线程#2 时不断更改其值。所以线程 #2 不会处理您希望它处理的范围。

我假设您希望每个线程处理数组中单独的索引范围?目前,您将指向数组开头的指针传递给函数,并使用全局变量将索引保存到您希望由该线程处理的块的数组中。

为避免使用该全局索引,您只需将一个指向偏移量的指针传递到您想要开始处理的数组中间。因此,与其传入指向开始元素 (array) 的值,不如传入一个指向要从其开始处理的元素 (array + result_number) 的值。

如果你这样做,在你的函数 primeNums() 中,它就像你传入的指针是一个数组的开头(即使它在中间的某个地方),你可以运行你的循环从 0 到 @ 987654329@,因为您在调用该函数之前已经添加了result_number

说了这么多,我怀疑你仍然无法并行处理这个数组(如果这确实是你想要做的),因为每个线程都依赖于 candidate 被设置为最大值从上一个线程...

为了保护“候选”不被启动其他线程的代码同时更改(如果您这样做),您可以在您的互斥锁(锁)上同步后获取该变量的副本。但是,老实说,我不确定这个算法是否会让你并行这个处理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-04
    • 2021-01-12
    • 2022-01-05
    • 2016-03-07
    • 2012-03-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多