2012-09-04 74 views
0

我對Pthread有個棘手的問題,我找不出來。我使用互斥體來同步子線程和主線程。但是,當我在主線程中鎖定subFinished [i]時,它無法鎖定,並卡在那裏。有時候它會很好,尤其是當我在代碼中插入一些std輸出時。但大多數情況下,它會在試圖鎖定互斥鎖subFinished [i]時卡住。使用互斥體的Pthread同步

是否有任何不可預知的事情會發生在我同步線程的方式?

明天的作業。很多thx!

代碼是如下面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` 

進行編譯。

回答

2

哦,我犯了一個致命的錯誤,我把pthread_create放在mutex_init之前,這會導致不可預知的結果。

+0

+1用於調試/修復自己的錯誤! –