0

我遇到了一个关于 Pthread 的棘手问题,我无法弄清楚。我使用互斥锁来同步子线程和主线程。但是,当我将 subFinished[i] 锁定在主线程中时,它无法将其锁定并卡在那里。有时进展顺利,尤其是当我在代码中插入一些标准输出时。但大多数情况下,它会在尝试锁定 mutex subFinished[i] 时卡住。

在我同步线程的方式中是否会发生任何不可预知的事情?

明天交作业。很多谢谢!

代码如下C中。

#include <stdio.h>
#include <math.h>
#include <memory.h>
#include <time.h>
#include <stdlib.h>

#include <gtk/gtk.h>

#include <pthread.h>

#define MAP_SIZE 10 

#define WALL_TEMP 20
#define FIREPLACE_TEMP 100

#define MAX_THREAD_NUM 64

#define start_time clock_gettime(CLOCK_MONOTONIC, &start);
#define end_time clock_gettime(CLOCK_MONOTONIC, &finish);

pthread_barrier_t diff_barrier;

struct timespec start, finish;

const double SHRESHOLD = 1.0e-2;

GtkWidget *window;
GtkWidget *draw_area;
GdkColor temp_color;

int iter_cnt, iter_times;

int strip_height;
int row_start, row_end;

//double x[MAP_SIZE+2][MAP_SIZE+2], x_new[MAP_SIZE+2][MAP_SIZE+2];

double diff[MAX_THREAD_NUM];

int msgtag=0;

pthread_t threads[MAX_THREAD_NUM];
int start_idx[MAX_THREAD_NUM];
int end_idx[MAX_THREAD_NUM];

int thread_n;

int converged = 0;

pthread_mutex_t subThreadWakeup[MAX_THREAD_NUM];
pthread_mutex_t subFinished[MAX_THREAD_NUM];

double **x_pointer, **x_new_pointer;

double *x, *x_new;
void *thread_work(void *arg){
    int thread_id = *(int*)arg;
    int row_start = start_idx[thread_id] ;
    int row_end = end_idx[thread_id];   
    while(1){
        pthread_mutex_lock(&subThreadWakeup[thread_id]);
        printf("Thread#%d get lock %d\n", thread_id, thread_id);
        if(converged)
            break;
        int i, j;
        for(i=row_start; i<=row_end; i++){
            for(j=1; j<=MAP_SIZE;j++){
                x_new_pointer[i][j] = (x_pointer[i][j-1] + x_pointer[i][j+1] + x_pointer[i-1][j] + x_pointer[i+1][j])/4;
                diff[thread_id] += (x_new_pointer[i][j] - x_pointer[i][j]) * (x_new_pointer[i][j] - x_pointer[i][j]);
            }
        }

        printf("thread#%d finished, but not unlock subFinished[%d].\n", thread_id, thread_id);
        //printf("mutex unlock: %d\n", pthread_mutex_unlock(&subFinished[thread_id]));
//      subFinished[i] = 1;
        pthread_mutex_unlock(&subFinished[thread_id]);
        printf("thread#%d finished, already unlock subFinished[%d].\n", thread_id, thread_id);
    }
    pthread_exit(NULL);
}
#ifdef DISPLAY
static gboolean expose_event_callback(GtkWidget *widget){
    GdkGC *gc = widget->style->fg_gc[GTK_WIDGET_STATE(widget)];
    GdkDrawable *drawable = widget->window;

    int i, j;
    for(i=1; i<=MAP_SIZE; i++){
        for(j=1; j<=MAP_SIZE; j++){
            temp_color.red = (int)(x[i][j])*(0xffff)/(5*20);
            temp_color.green = temp_color.blue = temp_color.red/2;
            gdk_gc_set_rgb_fg_color(gc, &temp_color);
            gdk_draw_point(drawable, gc, j, i);
        }
    }
}
#endif

int main(int argc, char *argv[]){

    int i,j,k;
    int tids[MAX_THREAD_NUM];
    for(i=0; i<MAX_THREAD_NUM; i++)
        tids[i] = i;

    if(argc > 1)
        thread_n = atoi(argv[1]);
    else
        thread_n = 1;

    if(argc > 2)
        iter_times = atoi(argv[2]);
    else
        iter_times = 0;

    printf("%d\n", thread_n + 1);
    // Specify the start_idx and end_idx
    int remainder = MAP_SIZE % thread_n;

    for(i=0; i<thread_n; i++){
        if(i==0) start_idx[i] = 1;
        else start_idx[i] = end_idx[i-1]+1;
        end_idx[i] = start_idx[i] + MAP_SIZE/thread_n + (i<remainder) - 1;
    }

    x = malloc(sizeof(double)*(MAP_SIZE+2)*(MAP_SIZE+2));
    x_new = malloc(sizeof(double)*(MAP_SIZE+2)*(MAP_SIZE+2));
    x_pointer = malloc(sizeof(double*)*(MAP_SIZE+2));
    x_new_pointer = malloc(sizeof(double*)*(MAP_SIZE+2));

    for(i=0; i<MAP_SIZE+2; i++) x_pointer[i] = &x[i*(MAP_SIZE+2)];
    for(i=0; i<MAP_SIZE+2; i++) x_new_pointer[i] = &x_new[i*(MAP_SIZE+2)];
    // Specify x matrix
    for(j=0; j<0.3*MAP_SIZE; j++)
        x_pointer[0][j] = WALL_TEMP;
    for(j=0.7*MAP_SIZE; j<MAP_SIZE+1; j++)
        x_pointer[0][j] = WALL_TEMP;
    for(j=0.3*MAP_SIZE; j<0.7*MAP_SIZE; j++)
        x_pointer[0][j] = FIREPLACE_TEMP;

    for(j=0; j<MAP_SIZE+2; j++)
        x_pointer[MAP_SIZE+1][j]=WALL_TEMP;

    for(i=0; i<MAP_SIZE+2; i++){
        x_pointer[i][0] = WALL_TEMP;
        x_pointer[i][MAP_SIZE+1] = WALL_TEMP;
    }

    // initialize x_new the same way as x
    for(i=0; i<=MAP_SIZE+1; i++)
        for(j=0; j<=MAP_SIZE+1;j ++)
            x_new_pointer[i][j] = x_pointer[i][j];

    for(i=0; i<thread_n; i++){
        pthread_create(&threads[i], NULL, thread_work, &tids[i]);
        printf("create %d\n", tids[i]);
    }

    for(i=0; i<thread_n; i++){
        pthread_mutex_init(&subThreadWakeup[i], NULL);
        pthread_mutex_init(&subFinished[i], NULL);
        pthread_mutex_lock(&subThreadWakeup[i]);
        pthread_mutex_lock(&subFinished[i]);
    }


    double total_diff = 0;
    start_time
    do{
        iter_cnt ++;
        total_diff = 0;     
        memset(diff, 0.0, thread_n * sizeof(double));
        for(i=0; i<thread_n; i++){
            pthread_mutex_unlock(&subThreadWakeup[i]);
        }

        printf("++");
        printf("all wake up.");

        for(i=0; i<thread_n; i++){
            printf("Try get lock %d\n", i);

            pthread_mutex_lock(&subFinished[i]);

            printf("Get Lock %d\n", i);
        }
        printf("all finished.\n");
        fflush(stdout);
        double **tmp_pointer = x_pointer;
        x_pointer = x_new_pointer;
        x_new_pointer = tmp_pointer;

        for(i=0; i<thread_n; i++)
            total_diff += diff[i];
        printf("total_diff: %lf\n", total_diff);
    }while( sqrt(total_diff) >= SHRESHOLD && !(iter_cnt >= iter_times && iter_times));

    converged = 1;

    for(i=0; i<thread_n; i++)
        pthread_mutex_unlock(&subThreadWakeup[i]);

    end_time
    printf("%d %d %lf\n", thread_n, iter_cnt, finish.tv_sec-start.tv_sec + (double)(finish.tv_nsec - start.tv_nsec)/ 1000000000.0);

#ifdef DISPLAY
    gtk_init(&argc, &argv);
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_widget_set_size_request(window, MAP_SIZE, MAP_SIZE);
    gtk_window_set_title(window, "Heat Distribution");

    draw_area = gtk_drawing_area_new();
    gtk_widget_set_size_request(draw_area, MAP_SIZE, MAP_SIZE);
    gtk_container_add(GTK_CONTAINER(window), draw_area);    

    g_signal_connect(G_OBJECT(draw_area), "expose_event", G_CALLBACK(expose_event_callback), NULL);
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);

    gtk_widget_show_all(window);



    gtk_main();
#endif
    return 0;
}

使用

$ gcc -O2 -o pthread_mutex pthread_mutex.c -lm -lrt -lpthread `pkg-config --cflags --libs gtk+-2.0`

编译。

4

1 回答 1

2

哦,我犯了一个致命的错误,我把 pthread_create 放在 mutex_init 之前,这会导致不可预知的结果。

于 2012-09-04T04:36:38.217 回答