开发者

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"
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜