我遇到了一个关于 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`
编译。