如何获得正确的pthreads执行顺序

时间:2014-04-24 20:41:29

标签: c pthreads histogram

我正在使用pthreads做直方图并经过长时间的努力...最后它说:

Segmentation Fault (Core Dumped) 

不幸的是我有这条线

p=(struct1 *)malloc(sizeof(struct1)); 

从命令行获取结构变量的值后..所以这被清除了..感谢@DNT让我知道..

现在当我尝试执行以下程序时..它有时会显示输出,有时它会转到which_bin函数并输出以下内容

output type 1(which is not the correct output): 
Data = 0.000000 doesn't belong to a bin! 
Quitting

output type 2(almost the correct output of histo with time taken by threads): 
10.000-28.000: 
28.000-46.000: 
46.000-64.000: 
64.000-82.000: 
82.000-100.000: XXXXXXXXXX 
The code to be timed took 0.000415 seconds

我的问题是为什么当跑步显示不同的输出时同样的编程...我很困惑它正是在寻找...

    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include "timer.h"
    void Usage(char prog_name[]);

    void Gen_data(void *p);
    void Gen_bins(void *p);
    int Which_bin(void *p);
    void Print_histo(void *p);


    void func(void *p);

    struct test
    {
     int bin_count, i, bin;
     float min_meas, max_meas;
     float* bin_maxes;
     int* bin_counts;
     int data_count;
     float* data;
    };

    typedef struct test struct1;

    int main(int argc, char* argv[])
    {
    double start, finish, elapsed;
    GET_TIME(start);

    struct1 *p;
    pthread_t th1, th2, th3;

    p=(struct1 *)malloc(sizeof(struct1));
    if (argc != 5)
        Usage(argv[0]);
    p->bin_count = strtol(argv[1], NULL, 10);
    p->min_meas = strtof(argv[2], NULL);
    p->max_meas = strtof(argv[3], NULL);
    p->data_count = strtol(argv[4], NULL, 10);

    p->bin_maxes = malloc(p->bin_count*sizeof(float));
    p->bin_counts = malloc(p->bin_count*sizeof(int));
    p->data = malloc(p->data_count*sizeof(float));


    pthread_create(&th1,NULL,(void*) Gen_data,(void*) p);
    pthread_create(&th2,NULL,(void*) Gen_bins,(void*) p);
    pthread_create(&th3,NULL,(void*) func,(void*) p);
    printf("Hi\n");


    pthread_join(th1,NULL);
    pthread_join(th2,NULL);
    pthread_join(th3,NULL);


    Print_histo(p);
    free(p->data);
    free(p->bin_maxes);
    free(p->bin_counts);

    GET_TIME(finish);
    elapsed = finish - start;
    printf("The code to be timed took %f seconds\n", elapsed);
    return 0;
}  /* main */

void func(void *p)
{
    int i;
    struct1 *args;
    args=(struct1*)p;

    for (i = 0; i < args->data_count; i++)
    {
        args->bin = Which_bin(args);
        args->bin_counts[args->bin]++;
    }

    #  ifdef DEBUG
        printf("bin_counts = ");
        for (i = 0; i < args->bin_count; i++)
            printf("%d ", args->bin_counts[i]);
        printf("\n");
    #  endif
}

/*---------------------------------------------------------------------
 * Function:  Usage
 * Purpose:   Print a message showing how to run program and quit
 * In arg:    prog_name:  the name of the program from the command line
 */
void Usage(char prog_name[] /* in */)
{
    fprintf(stderr, "usage: %s ", prog_name);
    fprintf(stderr, "<bin_count> <min_meas> <max_meas> <data_count>\n");
    exit(0);
}  /* Usage */


void Gen_data(void *p)
{
    struct1 *args;
    args=(struct1*)p;
    int i;
    srandom(0);
    for (i = 0; i < args->data_count; i++)
        args->data[i] = args->min_meas + (args->max_meas - args->min_meas)*random()/((double) RAND_MAX);

    #ifdef DEBUG
        printf("data = ");
        for (i = 0; i < args->data_count; i++)
            printf("%4.3f ", args->data[i]);
        printf("\n");
    #endif
} /* Gen_data */


void Gen_bins(void* p)
{
    struct1 *args;
    args=(struct1*)p;
    float bin_width;
    int   i;
    bin_width = (args->max_meas - args->min_meas)/args->bin_count;

    for (i = 0; i < args->bin_count; i++)
    {
        args->bin_maxes[i] = args->min_meas + (i+1)*bin_width;
        args->bin_counts[i] = 0;
    }

    #  ifdef DEBUG
        printf("bin_maxes = ");
        for (i = 0; i < args->bin_count; i++)
            printf("%4.3f ", args->bin_maxes[i]);
        printf("\n");
    #  endif
}

int Which_bin(void* p)
{
    struct1 *args;
    args=(struct1*)p;
    int bottom = 0, top =  args->bin_count-1;
    int mid;
    float bin_max, bin_min;

    while (bottom <= top)
    {
        mid = (bottom + top)/2;
        bin_max = args->bin_maxes[mid];
        bin_min = (mid == 0) ? args->min_meas: args->bin_maxes[mid-1];
        if (*(args->data) >= bin_max)
            bottom = mid+1;
        else if (*(args->data) < bin_min)
            top = mid-1;
        else
            return mid;
    }
    fprintf(stderr, "Data = %f doesn't belong to a bin!\n", args->data);
    fprintf(stderr, "Quitting\n");
    exit(-1);
}

void Print_histo(void *p)
{
    struct1 *args;
    args=(struct1*)p;
    int i, j;
    float bin_max, bin_min;

    for (i = 0; i < args->bin_count; i++)
    {
        bin_max = args->bin_maxes[i];
        bin_min = (i == 0) ? args->min_meas: args->bin_maxes[i-1];
        printf("%.3f-%.3f:\t", bin_min, bin_max);
        for (j = 0; j < args->bin_counts[i]; j++)
            printf("X");
        printf("\n");
    }
}

/* Print_histo */    #include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "timer.h"
void Usage(char prog_name[]);

void Gen_data(void *p);
void Gen_bins(void *p);
int Which_bin(void *p);
void Print_histo(void *p);

void func(void *p);

pthread_mutex_t lock;
struct test
{
    int bin_count, i, bin;
    float min_meas, max_meas;
    float* bin_maxes;
    int* bin_counts;
    int data_count;
    float* data;
};

typedef struct test struct1;

int main(int argc, char* argv[])
{
    if (pthread_mutex_init(&lock, NULL) != 0)
    {
        printf("\n mutex init failed\n");
        return 1;
    }
    double start, finish, elapsed;
    GET_TIME(start);

    struct1 *p;
    pthread_t th1, th2, th3;

    p=(struct1 *)malloc(sizeof(struct1));
    if (argc != 5)
        Usage(argv[0]);
    p->bin_count = strtol(argv[1], NULL, 10);
    p->min_meas = strtof(argv[2], NULL);
    p->max_meas = strtof(argv[3], NULL);
    p->data_count = strtol(argv[4], NULL, 10);

    p->bin_maxes = malloc(p->bin_count*sizeof(float));
    p->bin_counts = malloc(p->bin_count*sizeof(int));
    p->data = malloc(p->data_count*sizeof(float));


    pthread_create(&th1,NULL,(void*) Gen_data,(void*) p);
    pthread_create(&th2,NULL,(void*) Gen_bins,(void*) p);
    pthread_create(&th3,NULL,(void*) func,(void*) p);
    printf("Hi\n");


    pthread_join(th1,NULL);
    pthread_join(th2,NULL);
    pthread_join(th3,NULL);


    Print_histo(p);
    free(p->data);
    free(p->bin_maxes);
    free(p->bin_counts);

    GET_TIME(finish);
    elapsed = finish - start;
    printf("The code to be timed took %f seconds\n", elapsed);
    return 0;
}  /* main */

void func(void *p)
{
    pthread_mutex_lock(&lock);
    printf("th3 from Gen_func\n");
    int i;
    struct1 *args;
    args=(struct1*)p;

    for (i = 0; i < args->data_count; i++)
    {
        args->bin = Which_bin(args);
        args->bin_counts[args->bin]++;
    }

    #  ifdef DEBUG
        printf("bin_counts = ");
        for (i = 0; i < args->bin_count; i++)
            printf("%d ", args->bin_counts[i]);
        printf("\n");
    #  endif
    pthread_mutex_unlock(&lock);
}

/*---------------------------------------------------------------------
 * Function:  Usage
 * Purpose:   Print a message showing how to run program and quit
 * In arg:    prog_name:  the name of the program from the command line
 */
void Usage(char prog_name[] /* in */)
{
    fprintf(stderr, "usage: %s ", prog_name);
    fprintf(stderr, "<bin_count> <min_meas> <max_meas> <data_count>\n");
    exit(0);
}  /* Usage */


void Gen_data(void *p)
{
    pthread_mutex_lock(&lock);
    printf("th1 from Gen_data\n");
    struct1 *args;
    args=(struct1*)p;
    int i;
    srandom(0);
    for (i = 0; i < args->data_count; i++)
        args->data[i] = args->min_meas + (args->max_meas - args->min_meas)*random()/((double) RAND_MAX);

    #ifdef DEBUG
        printf("data = ");
        for (i = 0; i < args->data_count; i++)
            printf("%4.3f ", args->data[i]);
        printf("\n");
    #endif
    pthread_mutex_unlock(&lock);
} /* Gen_data */


void Gen_bins(void* p)
{
    pthread_mutex_lock(&lock);
    printf("th2 from Gen_bins\n");
    struct1 *args;
    args=(struct1*)p;
    float bin_width;
    int   i;
    bin_width = (args->max_meas - args->min_meas)/args->bin_count;

    for (i = 0; i < args->bin_count; i++)
    {
        args->bin_maxes[i] = args->min_meas + (i+1)*bin_width;
        args->bin_counts[i] = 0;
    }

    #  ifdef DEBUG
        printf("bin_maxes = ");
        for (i = 0; i < args->bin_count; i++)
            printf("%4.3f ", args->bin_maxes[i]);
        printf("\n");
    #  endif
    pthread_mutex_unlock(&lock);
}

int Which_bin(void* p)
{
    struct1 *args;
    args=(struct1*)p;
    int bottom = 0, top =  args->bin_count-1;
    int mid;
    float bin_max, bin_min;

    while (bottom <= top)
    {
        mid = (bottom + top)/2;
        bin_max = args->bin_maxes[mid];
        bin_min = (mid == 0) ? args->min_meas: args->bin_maxes[mid-1];
        if (*(args->data) >= bin_max)
            bottom = mid+1;
        else if (*(args->data) < bin_min)
            top = mid-1;
        else
            return mid;
    }
    fprintf(stderr, "Data = %f doesn't belong to a bin!\n", args->data);
    fprintf(stderr, "Quitting\n");
    exit(-1);
}

void Print_histo(void *p)
{
    struct1 *args;
    args=(struct1*)p;
    int i, j;
    float bin_max, bin_min;

    for (i = 0; i < args->bin_count; i++)
    {
        bin_max = args->bin_maxes[i];
        bin_min = (i == 0) ? args->min_meas: args->bin_maxes[i-1];
        printf("%.3f-%.3f:\t", bin_min, bin_max);
        for (j = 0; j < args->bin_counts[i]; j++)
            printf("X");
        printf("\n");
    }
}

/* Print_histo */

我添加了行以查看所有线程是否正在访问其功能..我观察到了这一点..

output 1:
Hi
th1 from Gen_data
th3 from Gen_func
Data = 0.000000 doesn't belong to a bin!
Quitting

在输出1中,我可以看到th2没有执行,程序结束显示错误..

output 2:
th1 from Gen_data
Hi
th2 from Gen_bins
th3 from Gen_func
10.000-28.000:
28.000-46.000:
46.000-64.000:
64.000-82.000:
82.000-100.000: XXXXXXXXXX
The code to be timed took 0.000348 seconds

在输出2中,所有线程都被执行,输出也是如此..

我很困惑,为什么线程th2没有被执行,我如何确保所有线程以正确的顺序运行..

我想知道该程序是否在逻辑错误?如果在逻辑上这是错误的,为什么它有时会显示直方图输出..谢谢!

1 个答案:

答案 0 :(得分:0)

无法保证线程执行顺序。在现代的多核处理器上,线程甚至可以同时执行。无法保证Gen_bins线程在func线程之前完成。由于您的线程访问和操作相同的数据结构,因此您注意到结果是不可预测的。

虽然我认为此应用程序不需要线程,但请进行以下更改以确保线程按列出的顺序执行。变化:

pthread_create(&th1,NULL,(void*) Gen_data,(void*) p);
pthread_create(&th2,NULL,(void*) Gen_bins,(void*) p);
pthread_create(&th3,NULL,(void*) func,(void*) p);
pthread_join(th1,NULL);
pthread_join(th2,NULL);
pthread_join(th3,NULL);

为:

pthread_create(&th1,NULL,(void*) Gen_data,(void*) p);
pthread_join(th1,NULL);
pthread_create(&th2,NULL,(void*) Gen_bins,(void*) p);
pthread_join(th2,NULL);
pthread_create(&th3,NULL,(void*) func,(void*) p);
pthread_join(th3,NULL);

这确保每个线程在下一次启动之前执行并完成。同样,由于线程不是并发执行的,因此该程序不需要线程化,只会增加复杂性。