多线程程序 - 核心转储
multi threaded program - core dumped
我正在尝试制作一个多线程素数计数器程序。我已经添加了关键代码以供理解(parseargs 函数在另一个程序中工作得很好,感觉没有必要,我不想让你用代码超载)。
长话短说,该程序编译并适用于小数字(最多 1000 个最大值和 8 个线程),但是当我尝试使用更大的数字时,我不断收到很多错误,例如:
分段错误:核心已转储,浮点异常,realloc():下一个大小无效。
代码有什么问题?我知道我应该使用更少的全局变量,但我正在努力让它发挥作用,然后我会变得更干净、更好。
我唯一使用 realloc 的地方是在 isprime 内部;在我的其他程序中效果很好。那里有什么问题?
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/mman.h>
void parseargs(char *argv[], int argc, int *lval, int *uval, int *nval, int *tval);
int isprime(int n);
void setFlags();
pthread_mutex_t num_lock;
pthread_mutex_t count_lock;
char *flagarr = NULL;
int num;
int lval = 1;//min value
int uval = 100;//max value
int count = 0;//primes counter
int main (int argc, char **argv)
{
int nval = 10;// how much numbers to print
int tval = 4;// threads number
num = lval;
if (pthread_mutex_init(&num_lock, NULL) != 0) {
printf("\n mutex init has failed\n");
return 1;
}
if (pthread_mutex_init(&count_lock, NULL) != 0) {
printf("\n mutex init has failed\n");
return 1;
}
// Parse arguments
parseargs(argv, argc, &lval, &uval, &nval, &tval);// works 100% (change the defult starting vals)
if (uval < lval)
{
fprintf(stderr, "Upper bound should not be smaller then lower bound\n");
exit(1);
}
if (lval < 2)
{
lval = 2;
uval = (uval > 1) ? uval : 1;
}
if (tval<1)
tval=4;
// Allocate flags
flagarr= (char *)malloc(sizeof(char) * (uval-lval+1));
if (flagarr == NULL)
exit(1);
//Allocate threads
pthread_t* t = (pthread_t *)malloc(sizeof(pthread_t)*tval);
if (t == NULL)
exit(1);
//start threads
for(int i =0; i<tval ; i++){
printf("%d\n",i);
pthread_create(&t[i],NULL,(void*)setFlags,NULL);
}
for(int i =0; i<tval ; i++)
pthread_join(t[i],NULL);
// Print results
nval=count;
printf("Found %d primes from %d to %d%c", count, lval,uval , count ? ' ' : '.');
if(count && nval>0)
printf("and printing the first %d of them:\n",nval);
else
printf("\n");
for (num = lval; (num <= uval) && (nval) ; num++)
if (flagarr[num - lval])
{
nval--;
count--;
printf("%d%c", num, (count && nval) ? ',' : '\n');
}
free(flagarr);
free(t);
return 0;
}
void setFlags()
{
int myNum;
for (; num <= uval;)
{
pthread_mutex_lock(&num_lock);
myNum=num;
num++;
pthread_mutex_unlock(&num_lock);
if (isprime(myNum))
{
flagarr[myNum - lval] = 1;
pthread_mutex_lock(&count_lock);
count ++;
pthread_mutex_unlock(&count_lock);
} else {
flagarr[myNum - lval] = 0;
}
}
}
int isprime(int n)
{
static int *primes = NULL; // NOTE: static !
static int size = 0; // NOTE: static !
static int maxprime; // NOTE: static !
int root;
int i;
// Init primes array (executed on first call)
pthread_mutex_lock(&first_lock);
if (primes == NULL)
{
primes = (int *)malloc(2*sizeof(int));
if (primes == NULL)
exit(1);
size = 2;
primes[0] = 2;
primes[1] = 3;
maxprime = 3;
}
pthread_mutex_unlock(&first_lock);
root = (int)(sqrt(n));
// Update primes array, if needed
while (root > maxprime)
for (i = maxprime + 2 ; ; i+=2)
if (isprime(i))
{
pthread_mutex_lock(&primeFunc_lock);
size++;
primes = (int *)realloc(primes, size * sizeof(int));
if (primes == NULL)
exit(1);
primes[size-1] = i;
maxprime = i;
pthread_mutex_unlock(&primeFunc_lock);
break;
}
// Check 'special' cases
if (n <= 0)
return -1;
if (n == 1)
return 0;
// Check prime
for (i = 0 ; ((i < size) && (root >= primes[i])) ; i++)
if ((n % primes[i]) == 0)
return 0;
return 1;
}
I know that I should use fewer global variables but I'm trying to make it work and then I will make cleaner and better.
对于多线程程序,这种方法行不通 -- 你不能先写一个有问题的程序,然后再把它变得漂亮,然后 bug-free -- 你 必须 先拿到bug-free
此外,全局和静态变量以及线程通常不会混用。
现在,正如其他人所指出的,您可以在 isprime()
中访问静态变量而无需任何锁定。想想线程T1执行这段代码会发生什么:
for (i = 0 ; ((i < size) && (root >= primes[i])) ; i++)
if ((n % primes[i]) == 0)
另一个线程T2同时执行这条语句:
primes = (int *)realloc(primes, size * sizeof(int));
由于 primes
不是原子变量,编译器(可能)会将 primes
的值加载到某个寄存器中,并在 T1 的整个循环中继续使用该值。循环将完全忘记 primes
可能已经在 T2 中被 free()
d 和 realloc()
ed,并且现在指向完全不同的内存块这一事实。 T1 将继续读取旧的(现在悬空的)内存。
您的 isprimes()
函数中存在类似的问题,很容易解释您观察到的崩溃。
如果您在 Linux 系统上,Thread sanitizer (and Address sanitizer) 是您的朋友。
我正在尝试制作一个多线程素数计数器程序。我已经添加了关键代码以供理解(parseargs 函数在另一个程序中工作得很好,感觉没有必要,我不想让你用代码超载)。
长话短说,该程序编译并适用于小数字(最多 1000 个最大值和 8 个线程),但是当我尝试使用更大的数字时,我不断收到很多错误,例如:
分段错误:核心已转储,浮点异常,realloc():下一个大小无效。
代码有什么问题?我知道我应该使用更少的全局变量,但我正在努力让它发挥作用,然后我会变得更干净、更好。 我唯一使用 realloc 的地方是在 isprime 内部;在我的其他程序中效果很好。那里有什么问题?
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/mman.h>
void parseargs(char *argv[], int argc, int *lval, int *uval, int *nval, int *tval);
int isprime(int n);
void setFlags();
pthread_mutex_t num_lock;
pthread_mutex_t count_lock;
char *flagarr = NULL;
int num;
int lval = 1;//min value
int uval = 100;//max value
int count = 0;//primes counter
int main (int argc, char **argv)
{
int nval = 10;// how much numbers to print
int tval = 4;// threads number
num = lval;
if (pthread_mutex_init(&num_lock, NULL) != 0) {
printf("\n mutex init has failed\n");
return 1;
}
if (pthread_mutex_init(&count_lock, NULL) != 0) {
printf("\n mutex init has failed\n");
return 1;
}
// Parse arguments
parseargs(argv, argc, &lval, &uval, &nval, &tval);// works 100% (change the defult starting vals)
if (uval < lval)
{
fprintf(stderr, "Upper bound should not be smaller then lower bound\n");
exit(1);
}
if (lval < 2)
{
lval = 2;
uval = (uval > 1) ? uval : 1;
}
if (tval<1)
tval=4;
// Allocate flags
flagarr= (char *)malloc(sizeof(char) * (uval-lval+1));
if (flagarr == NULL)
exit(1);
//Allocate threads
pthread_t* t = (pthread_t *)malloc(sizeof(pthread_t)*tval);
if (t == NULL)
exit(1);
//start threads
for(int i =0; i<tval ; i++){
printf("%d\n",i);
pthread_create(&t[i],NULL,(void*)setFlags,NULL);
}
for(int i =0; i<tval ; i++)
pthread_join(t[i],NULL);
// Print results
nval=count;
printf("Found %d primes from %d to %d%c", count, lval,uval , count ? ' ' : '.');
if(count && nval>0)
printf("and printing the first %d of them:\n",nval);
else
printf("\n");
for (num = lval; (num <= uval) && (nval) ; num++)
if (flagarr[num - lval])
{
nval--;
count--;
printf("%d%c", num, (count && nval) ? ',' : '\n');
}
free(flagarr);
free(t);
return 0;
}
void setFlags()
{
int myNum;
for (; num <= uval;)
{
pthread_mutex_lock(&num_lock);
myNum=num;
num++;
pthread_mutex_unlock(&num_lock);
if (isprime(myNum))
{
flagarr[myNum - lval] = 1;
pthread_mutex_lock(&count_lock);
count ++;
pthread_mutex_unlock(&count_lock);
} else {
flagarr[myNum - lval] = 0;
}
}
}
int isprime(int n)
{
static int *primes = NULL; // NOTE: static !
static int size = 0; // NOTE: static !
static int maxprime; // NOTE: static !
int root;
int i;
// Init primes array (executed on first call)
pthread_mutex_lock(&first_lock);
if (primes == NULL)
{
primes = (int *)malloc(2*sizeof(int));
if (primes == NULL)
exit(1);
size = 2;
primes[0] = 2;
primes[1] = 3;
maxprime = 3;
}
pthread_mutex_unlock(&first_lock);
root = (int)(sqrt(n));
// Update primes array, if needed
while (root > maxprime)
for (i = maxprime + 2 ; ; i+=2)
if (isprime(i))
{
pthread_mutex_lock(&primeFunc_lock);
size++;
primes = (int *)realloc(primes, size * sizeof(int));
if (primes == NULL)
exit(1);
primes[size-1] = i;
maxprime = i;
pthread_mutex_unlock(&primeFunc_lock);
break;
}
// Check 'special' cases
if (n <= 0)
return -1;
if (n == 1)
return 0;
// Check prime
for (i = 0 ; ((i < size) && (root >= primes[i])) ; i++)
if ((n % primes[i]) == 0)
return 0;
return 1;
}
I know that I should use fewer global variables but I'm trying to make it work and then I will make cleaner and better.
对于多线程程序,这种方法行不通 -- 你不能先写一个有问题的程序,然后再把它变得漂亮,然后 bug-free -- 你 必须 先拿到bug-free
此外,全局和静态变量以及线程通常不会混用。
现在,正如其他人所指出的,您可以在 isprime()
中访问静态变量而无需任何锁定。想想线程T1执行这段代码会发生什么:
for (i = 0 ; ((i < size) && (root >= primes[i])) ; i++)
if ((n % primes[i]) == 0)
另一个线程T2同时执行这条语句:
primes = (int *)realloc(primes, size * sizeof(int));
由于 primes
不是原子变量,编译器(可能)会将 primes
的值加载到某个寄存器中,并在 T1 的整个循环中继续使用该值。循环将完全忘记 primes
可能已经在 T2 中被 free()
d 和 realloc()
ed,并且现在指向完全不同的内存块这一事实。 T1 将继续读取旧的(现在悬空的)内存。
您的 isprimes()
函数中存在类似的问题,很容易解释您观察到的崩溃。
如果您在 Linux 系统上,Thread sanitizer (and Address sanitizer) 是您的朋友。