多线程应用程序中的段错误和不正确的输出
Segfault and incorrect output in multithreaded application
我正在学习 C 中的多线程,但在理解为什么我的代码没有给出预期的输出和段错误时遇到了一些麻烦。我在 C 中使用 pthread 库,我的代码启动了总共 m*2 个线程,m 用于它启动的两个函数中的每一个。第一个函数计算 30 个随机数并将其存储在全局数组中。然后第二个函数从数组中读取整数,计算它们的总和和平均值。第二个线程也用 pthread_join 等待第一个线程,但它似乎有时会在第一个线程退出之前加入。
我做错了什么?
我也知道使用互斥锁是一个更好的选择,但我正在尝试不使用互斥锁。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int n = 30;
int arr[100][30];
pthread_t tfirst[100];
pthread_t tsecond[100];
void *first(void *x){
for(int i = 0; i < n; i++)
arr[(int)x][i] = rand();
}
void *second(void *x){
pthread_join(tfirst[(int)x], NULL);
long sum = 0;
for(int i = 0; i < n; i++){
sum += arr[(int)x][n];
}
printf("Sum %d = %ld\n", (int)x + 1, sum);
sleep(1);
printf("Arithmetic mean %d = %f\n", (int)x + 1, (float)sum / n);
}
int main(int argc, char **argv){
int m;
srand(time(0));
if(argc < 2){
fprintf(stderr, "Usage: %s m [n]", argv[0]);
exit(EXIT_FAILURE);
}
m = atoi(argv[1]);
if(argc >= 3) n = atoi(argv[2]);
for(int i = 0; i < m; i++){
if (pthread_create(&tfirst[i], NULL, first, (void*)i)) {
fprintf(stderr, "Error creating thread!\n");
exit(EXIT_FAILURE);
}
if (pthread_create(&tsecond[i], NULL, second, (void*)i)) {
fprintf(stderr, "Error creating thread!\n");
exit(EXIT_FAILURE);
}
}
for(int i = 0; i < m; i++){
pthread_join(tfirst[i], NULL);
pthread_join(tsecond[i], NULL);
}
return 0;
}
您为同一个线程调用了两次 pthread_join
- 首先是在 second
线程例程中,然后是在 main
.
的末尾
The results of multiple simultaneous calls to pthread_join() specifying the same target thread are undefined.
The behavior is undefined if the value specified by the thread argument to pthread_join() does not refer to a joinable thread.
"If that thread has already terminated, then pthread_join() returns immediately" 部分意味着在已经结束(但仍可加入)的线程上调用 pthread_join
会立即调用 return ,但是在此调用线程之后不再可连接,再次调用 pthread_join
将导致 UB。
你的总和计算代码是错误的:sum += arr[(int)x][n];
将只使用第 n
个值(也就是越界导致 UB)。
此外,两个线程例程都应该 return 一个值:return NULL;
The second thread also waits for the first thread with pthread_join, but it seems to join sometimes before the first thread exits.
实际上,第二个线程甚至可以在第一个线程之前开始执行。关于线程执行顺序没有任何保证。
解决方案是只使用一个线程,即在 firts()
的末尾调用 second()
。这将保证这些函数之间的执行顺序没有任何互斥锁。
我正在学习 C 中的多线程,但在理解为什么我的代码没有给出预期的输出和段错误时遇到了一些麻烦。我在 C 中使用 pthread 库,我的代码启动了总共 m*2 个线程,m 用于它启动的两个函数中的每一个。第一个函数计算 30 个随机数并将其存储在全局数组中。然后第二个函数从数组中读取整数,计算它们的总和和平均值。第二个线程也用 pthread_join 等待第一个线程,但它似乎有时会在第一个线程退出之前加入。
我做错了什么?
我也知道使用互斥锁是一个更好的选择,但我正在尝试不使用互斥锁。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int n = 30;
int arr[100][30];
pthread_t tfirst[100];
pthread_t tsecond[100];
void *first(void *x){
for(int i = 0; i < n; i++)
arr[(int)x][i] = rand();
}
void *second(void *x){
pthread_join(tfirst[(int)x], NULL);
long sum = 0;
for(int i = 0; i < n; i++){
sum += arr[(int)x][n];
}
printf("Sum %d = %ld\n", (int)x + 1, sum);
sleep(1);
printf("Arithmetic mean %d = %f\n", (int)x + 1, (float)sum / n);
}
int main(int argc, char **argv){
int m;
srand(time(0));
if(argc < 2){
fprintf(stderr, "Usage: %s m [n]", argv[0]);
exit(EXIT_FAILURE);
}
m = atoi(argv[1]);
if(argc >= 3) n = atoi(argv[2]);
for(int i = 0; i < m; i++){
if (pthread_create(&tfirst[i], NULL, first, (void*)i)) {
fprintf(stderr, "Error creating thread!\n");
exit(EXIT_FAILURE);
}
if (pthread_create(&tsecond[i], NULL, second, (void*)i)) {
fprintf(stderr, "Error creating thread!\n");
exit(EXIT_FAILURE);
}
}
for(int i = 0; i < m; i++){
pthread_join(tfirst[i], NULL);
pthread_join(tsecond[i], NULL);
}
return 0;
}
您为同一个线程调用了两次 pthread_join
- 首先是在 second
线程例程中,然后是在 main
.
The results of multiple simultaneous calls to pthread_join() specifying the same target thread are undefined.
The behavior is undefined if the value specified by the thread argument to pthread_join() does not refer to a joinable thread.
"If that thread has already terminated, then pthread_join() returns immediately" 部分意味着在已经结束(但仍可加入)的线程上调用 pthread_join
会立即调用 return ,但是在此调用线程之后不再可连接,再次调用 pthread_join
将导致 UB。
你的总和计算代码是错误的:sum += arr[(int)x][n];
将只使用第 n
个值(也就是越界导致 UB)。
此外,两个线程例程都应该 return 一个值:return NULL;
The second thread also waits for the first thread with pthread_join, but it seems to join sometimes before the first thread exits.
实际上,第二个线程甚至可以在第一个线程之前开始执行。关于线程执行顺序没有任何保证。
解决方案是只使用一个线程,即在 firts()
的末尾调用 second()
。这将保证这些函数之间的执行顺序没有任何互斥锁。