pthreads on FreeBSD
I ve made a program that calculates prime numbers making use of pthread library. The program behaves well under cygwin and linux but not under FreeBSD.
Here is the program
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <math.h>
#define NUMTHREADS 5
#define N 10000
typedef struct
{
int start;
int end;
}DISTANCE;
int arr[N];
pthread_mutex_t mutex;
void *sieve(void* s)
{
int start,end,k,i,j;
DISTANCE* d = (DISTANCE*)s;
start = d->start;
end = d->end;
for(i=start;i<end;i++)
{
if(arr[i]==0)
{
k = i;
for(j=2*k;j<N+1;j+=i)
{
pthread_mutex_lock(&mutex);
arr[j] = 1;
pthread_mutex_unlock(&mutex);
}
}
}
pthread_exit(NULL);
}
void *fill_array(void* f)
{
int i;
arr[0] = 1;
arr[1] = 1;
for(i=2;i<N;i++)
{
arr[i] = 0;
}
pthread_exit(NULL);
}
int main(int argc, char **argv)
{
int div;
int status;
int i;
int count = 0;
int nums = 0;
pthread_t threads[NUMTHREADS];
DISTANCE dist[NUMTHREADS];
#ifdef NORMAL_FILL_ARRAY
arr[0] = 1;
arr[1] = 1;
for(i=2;i<N;i++)
{
arr[i] = 0;
}
#endif
#ifdef THREAD_FILL_ARRAY
pthread_t p_arr;
pthread_create(&p_arr, NULL, fill_array, (void *) NULL);
pthread_join(p_arr,NULL);
#endif
div = ((int)sqrt(N)+1)/NUMTHREADS;
pthread_mutex_init(&mutex, NULL);
for(i=0;i<NUMTHREADS;i++)
{
if(i==0)
{
dist[i].start = 2;
dist[i].end = 2 + div;
}
else if(i==NUMTHREADS-1)
{
dist[i].start = dist[i-1].end;
dist[i].end = (int)sqrt(N)+1;
}
else
{
dist[i].start = dist[i-1].end;
dist[i].end = dist[i].start + div;
}
pthread_create(&threads[i],NULL,sieve,(void *)&dist[i]);
}
for(i=0;i<NUMTHREADS;i++)
{
if(pthread_join(threads[i],(void **)&status)!=0)
printf("pthread_join error");
}
pthread_mutex_destroy(&mutex);
/*slower with print*/
for(i=0;i<N;i++)
{
if(arr[i]==0)
{
#ifdef PRINT
printf("%d\t",i);
count++;
#endif
nums++;
}
#ifdef PRINT
if(count==10)
{
printf("\n");
count = 0;
}
#endif
}
#ifdef PRINT
printf("\n");
#endif
printf("%d: prime numbers found!\n",nums);
pthread_exit(NULL);
return 0;
}
the Makefile
COMPILER=gcc
LIBS=-lpthread -lm
PRINT=-D PRINT
NORMAL=-D NORMAL_FILL_ARRAY
THREAD=-D THREAD_FILL_ARRAY
default:
$(COMPILER) $(NORMAL) p_sieve.c -o p_sieve $(LIBS)
threadfill:
$(COMPILER) $(THREAD) p_sieve.c -o p_sieve $(LIBS)
default_p:
$(COMPILER) $(NORMAL) $(PRINT) p_sieve.c -o p_sieve $(LIBS)
threadfill_p:
$(COMPILER) $(NORMAL) $(PRINT) p_sieve.c -o p_sieve $(LIBS)
debug:
$(COMPILER) $(NORMAL) -g p_sieve.c -o p_sieve $(LIBS)
clean:
开发者_高级运维 rm p_sieve
and finaly the gdb output
This GDB was configured as "i386-marcel-freebsd"...
(gdb) r
Starting program: /root/lab/src/sieve/p_sieve
[New LWP 100060]
[New Thread 28201140 (LWP 100060)]
[New Thread 28218140 (LWP 100085)]
[New Thread 28217ec0 (LWP 100090)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 28218140 (LWP 100085)]
0x28098f1f in pthread_mutex_unlock () from /lib/libthr.so.3
It seems that pthread_mutex_unlock produces this error but i cannot figure how to fix it. Can anyone help?
Without checking the details of your source code - is it possible that you are corrupting your memory somewhere - that would explain the strange SIGSEGV. Otherwise, I don't see a reason why pthread_mutex_unlock() would core dump.
Maybe try and remove all your array operations? Or put some extra bounds checking in there?
I don't remember exactly and have no FreeBSD at hand, but try compiling with -pthread flag.
int arr[N];
pthread_mutex_t mutex;
void *sieve(void* s)
{
int start,end,k,i,j;
DISTANCE* d = (DISTANCE*)s;
start = d->start;
end = d->end;
for(i=start;i<end;i++)
{
if(arr[i]==0)
{
k = i;
for(j=2*k;j<N+1;j+=i)
{
pthread_mutex_lock(&mutex);
/* Can write beyond the end of arr */
arr[j] = 1;
If I fix this bt limiting the for
loop to be < N
then it works, but with thread hazards.
Valgrind DRD:
==1700== Conflicting load by thread 3 at 0x006012d8 size 4
==1700== at 0x400B69: sieve (so10.c:28)
==1700== by 0x48620B8: ??? (in /usr/local/libexec/valgrind/vgpreload_drd-amd64-freebsd.so)
==1700== by 0x487B839: ??? (in /lib/libthr.so.3)
==1700== Allocation context: BSS section of /usr/home/paulf/scratch/so/so10/so10gcc
==1700== Other segment start (thread 2)
==1700== (thread finished, call stack no longer available)
==1700== Other segment end (thread 2)
==1700== (thread finished, call stack no longer available)
Valgrind Helgrind:
==1708== Lock at 0x60AEC0 was first observed
==1708== at 0x48544D8: pthread_mutex_init (in /usr/local/libexec/valgrind/vgpreload_helgrind-amd64-freebsd.so)
==1708== by 0x400C4F: main (so10.c:84)
==1708== Address 0x60aec0 is 0 bytes inside data symbol "mutex"
==1708==
==1708== Possible data race during read of size 4 at 0x6012D8 by thread #3
==1708== Locks held: none
==1708== at 0x400B69: sieve (so10.c:28)
==1708== by 0x485E066: ??? (in /usr/local/libexec/valgrind/vgpreload_helgrind-amd64-freebsd.so)
==1708== by 0x4871839: ??? (in /lib/libthr.so.3)
==1708==
==1708== This conflicts with a previous write of size 4 by thread #2
==1708== Locks held: 1, at address 0x60AEC0
==1708== at 0x400B93: sieve (so10.c:35)
==1708== by 0x485E066: ??? (in /usr/local/libexec/valgrind/vgpreload_helgrind-amd64-freebsd.so)
==1708== by 0x4871839: ??? (in /lib/libthr.so.3)
==1708== Address 0x6012d8 is 88 bytes inside data symbol "arr"
精彩评论