【发布时间】:2021-11-20 22:11:17
【问题描述】:
我正在尝试编写一个多线程 C 程序来查找区间中的所有素数。
单线程版本完美运行,但多线程版本存在重要问题,特别是由线程生命周期引起的。
这是代码:
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <pthread.h>
#define THREADS_NUM 4
struct ipp_args{
int id; // ID of the thread
int stop; // Max number to test
};
void *prime_checker(void*);
pthread_t threads[THREADS_NUM];
int count = 0;
int main(int argc, char const *argv[]) {
int start, end;
if (argc == 1) {
start = 2;
end = 100;
} else if (argc == 3) {
start = atoi(argv[1]);
end = atoi(argv[2]);
} else {
printf("Usage:\n\tprimes <from> <to>\n");
exit(1);
}
if (start < 2) start = 2;
// Launch threads
for (int thread_id = 0; thread_id < THREADS_NUM; ++thread_id) {
struct ipp_args args;
args.id = thread_id;
args.stop = end;
printf("[MAIN] Starting T_%d\n", thread_id);
int error = pthread_create(&threads[thread_id], NULL, prime_checker, (void*)&args);
if (error) {
printf("[MAIN] Cannot create thread %d\n", thread_id);
exit(3);
}
}
// Join threads
for (int thread_id = 0; thread_id < THREADS_NUM; thread_id++) {
printf("[MAIN] Joining T_%d\n", thread_id);
int error = pthread_join(threads[thread_id], NULL);
if (error) {
printf("[MAIN] Cannot join thread %d\n", thread_id);
exit(4);
}
}
printf("%d primes found\n", count);
pthread_exit(NULL);
return 0;
}
void *prime_checker(void *_args) {
struct ipp_args *args = _args;
int id = args->id;
int stop = args->stop;
printf("[T_%d] Started!\n", id);
for (int n = 2 + id; n < stop; n += THREADS_NUM) {
//printf("[T_%d] Checking %d\n", id, n);
int limit = sqrt(n);
bool prime = true;
for (int i = 2; i <= limit; i++) {
if (n % i == 0) {
prime = false;
break;
}
}
if (prime) count++;
}
pthread_exit(NULL);
return NULL;
}
运行代码会在每次运行时返回不同的输出,以下是一些示例:
[MAIN] Starting T_0
[MAIN] Starting T_1
[MAIN] Starting T_2
[MAIN] Starting T_3
[MAIN] Joining T_0
[T_3] Started!
[T_3] Started!
[T_3] Started!
[T_3] Started!
[MAIN] Joining T_1
[MAIN] Joining T_2
[MAIN] Joining T_3
44 primes found
[MAIN] Starting T_0
[MAIN] Starting T_1
[T_1] Started!
[T_2] Started!
[MAIN] Starting T_2
[MAIN] Starting T_3
[MAIN] Joining T_0
[T_3] Started!
[MAIN] Joining T_1
[MAIN] Joining T_2
[T_3] Started!
[MAIN] Joining T_3
35 primes found
[MAIN] Starting T_0
[MAIN] Starting T_1
[MAIN] Starting T_2
[T_2] Started!
[T_2] Started!
[MAIN] Starting T_3
[T_3] Started!
[MAIN] Joining T_0
[T_3] Started!
[MAIN] Joining T_1
[MAIN] Joining T_2
[MAIN] Joining T_3
22 primes found
有些线程有时会被多次调用,而另一些则根本不被调用。 如果有人知道如何解决此问题或可能是什么原因,请告诉我。
【问题讨论】:
-
常见错误。
struct ipp_args args;的生命周期为 一次 迭代。变量在每次迭代结束时变为无效。到线程看到变量时,它可以具有任何不确定的值。需要在循环外声明这些结构的数组,并且需要将不同的地址传递给每个线程。 -
您可能会考虑使用 OpenMP 来并行化您现有的单线程算法。
-
这不是并行性,而是多个线程执行相同的事情,然后将它们的结果相加。
标签: c multithreading pthreads