hello morris
compile_app2
Description: Binary data
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <mpfr.h> #include <string.h> #include <gtk/gtk.h> #include <sys/time.h> #include <errno.h>
/* build with: gcc threaded_app.c -o threaded_app -Wall -pedantic -std=gnu99 -lgmp -lmpfr -pthread -D_REENTRANT -ggdb `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0` */ typedef struct { struct timeval tv_start; struct timeval tv_end; } Timer; void timer_start(Timer* t) { gettimeofday(&t->tv_start, 0); } void timer_stop(Timer* t) { gettimeofday(&t->tv_end, 0); } long timer_get_elapsed(Timer* t) { if (t->tv_start.tv_sec == t->tv_end.tv_sec) return t->tv_end.tv_usec - t->tv_start.tv_usec; else return (t->tv_end.tv_sec - t->tv_start.tv_sec) * 1e6 + (t->tv_end.tv_usec - t->tv_start.tv_usec); } #define NTHREADS 8 #define IMG_WIDTH 480 #define IMG_HEIGHT 360 #if (G_BYTE_ORDER == G_BIG_ENDIAN) # define RGB(r,g,b) ((r) << 24 | ((g) << 16) | ((b) << 8)) # define RED(x) (((x) & 0xff000000) >> 24) # define GREEN(x) (((x) & 0x00ff0000) >> 16) # define BLUE(x) (((x) & 0x0000ff00) >> 8) #elif (G_BYTE_ORDER == G_LITTLE_ENDIAN) # define RGB(r,g,b) ((r) | ((g) << 8) | ((b) << 16)) # define RED(x) ((x) & 0x000000ff) # define GREEN(x) (((x) & 0x0000ff00) >> 8) # define BLUE(x) (((x) & 0x00ff0000) >> 16) #else # error Your machine has an unsupported byte order. Please send patch :) #endif typedef struct { int* arr; guint32* rgb_data; int next_line; int lines_done; int rendering; int start; int stop; pthread_t rend[NTHREADS]; int all_quit; int width; int height; double xmin, xmax, ymax; int depth; gint gui_idle_id; char* lines_rendered; char* lines_drawn; int min_rendered; int min_drawn; } image_info; static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data); static void destroy(GtkWidget *widget, gpointer data); void gui_start_render(GtkWidget* widget, gpointer data); void gui_stop_render(GtkWidget* widget, gpointer data); gint gui_idle_draw_cb(image_info* img); GtkWidget* gui_pbar = NULL; GtkWidget* drawing_area; void *render(void* ptr); int next_line(image_info* img); void* watch_render_start(void* ptr); void* watch_render_stop(void* ptr); void* watch_render_done(void* ptr); void* threads_render_create(void* ptr); pthread_mutex_t next_line_mutex = PTHREAD_MUTEX_INITIALIZER; //pthread_mutex_t lines_done_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t img_start_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t img_stop_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t img_rendering_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t img_start_cond = PTHREAD_COND_INITIALIZER; pthread_cond_t img_stop_cond = PTHREAD_COND_INITIALIZER; pthread_cond_t img_done_cond = PTHREAD_COND_INITIALIZER; pthread_cond_t lines_rendered_cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t img_lines_rendered_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t all_quit_mutex = PTHREAD_MUTEX_INITIALIZER; int main(int argc, char **argv) { printf("initializing...\n"); image_info* img = malloc(sizeof(image_info)); memset(img, 0, sizeof(image_info)); img->start = 0; img->width = IMG_WIDTH; img->height = IMG_HEIGHT; img->xmin = -2.0; img->xmax = 1.5; img->ymax = 1.25; img->depth = 300; img->xmin = -7.6243636067708333333333328e-1; img->xmax = -7.6243355758101851851851869e-1; img->ymax = 7.7996663411458333333333929e-2; img->depth = 30000; img->gui_idle_id = -1; size_t y_asz = img->height * sizeof(int); size_t xy_asz = img->width * y_asz; printf("creating array size: %ld bytes\n", xy_asz); img->arr = malloc(xy_asz); if (!img->arr) { fprintf(stderr, "image dimension too large!\n"); free(img); exit(-1); } memset(img->arr, 0, xy_asz); // img->lines_rendered = malloc(y_asz); img->lines_rendered = malloc(img->height); if (!img->lines_rendered) { fprintf(stderr, "image dimension too large!\n"); free(img->arr); free(img); exit(-1); } // img->lines_drawn = malloc(y_asz); img->lines_drawn = malloc(img->height); if (!img->lines_drawn) { fprintf(stderr, "image dimension too large!\n"); free(img->lines_rendered); free(img->arr); free(img); exit(-1); } img->rgb_data = g_malloc(img->width * img->height * sizeof(guint32)); int rc_err; pthread_t thread_start; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); printf("creating watch render start thread...\n"); rc_err = pthread_create(&thread_start, &attr, &watch_render_start, (void*)img); if (rc_err) { fprintf(stderr, "Thread start creation failed: %d\n", rc_err); free(img->lines_drawn); free(img->lines_rendered); free(img->arr); free(img); exit(-1); } printf("creating GUI...\n"); GtkWidget* window; GtkWidget* startbutton; GtkWidget* stopbutton; GtkWidget* vbox; GtkWidget* hbox; gtk_init(&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (delete_event), NULL); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL); gtk_container_set_border_width (GTK_CONTAINER (window), 10); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER (window), vbox); hbox = gtk_hbox_new(FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); startbutton = gtk_button_new_with_label ("Start render"); g_signal_connect (G_OBJECT (startbutton), "clicked", G_CALLBACK (gui_start_render), img); gtk_box_pack_start(GTK_BOX(hbox), startbutton, TRUE, TRUE, 0); stopbutton = gtk_button_new_with_label ("Stop render"); g_signal_connect (G_OBJECT (stopbutton), "clicked", G_CALLBACK (gui_stop_render), img); gtk_box_pack_start(GTK_BOX(hbox), stopbutton, TRUE, TRUE, 0); gui_pbar = gtk_progress_bar_new(); gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(gui_pbar), GTK_PROGRESS_LEFT_TO_RIGHT); gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(gui_pbar), (gfloat)1.0 ); /* img->real_height); */ gtk_widget_set_size_request(gui_pbar, 75, 0); gtk_box_pack_end(GTK_BOX(hbox), gui_pbar, FALSE, FALSE, 0); drawing_area = gtk_drawing_area_new(); /* gtk_widget_set_events (drawing_area, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_EXPOSURE_MASK); */ gtk_widget_set_size_request(drawing_area, img->width, img->height); gtk_box_pack_start(GTK_BOX(vbox), drawing_area, TRUE, TRUE, 0); /* g_signal_connect(GTK_OBJECT(tmp), "button_press_event", G_CALLBACK(button_press_event), NULL); g_signal_connect(GTK_OBJECT(tmp), "button_release_event", G_CALLBACK(button_release_event), NULL); g_signal_connect(GTK_OBJECT(tmp), "expose_event", G_CALLBACK(expose_event), img); g_signal_connect(GTK_OBJECT(tmp), "motion_notify_event", G_CALLBACK(motion_event), NULL); */ gtk_widget_show(startbutton); gtk_widget_show(stopbutton); gtk_widget_show(drawing_area); gtk_widget_show(hbox); gtk_widget_show(vbox); gtk_widget_show(window); printf("starting GUI\n"); gtk_main (); printf("************************\n" "GUI shutdown\n" "************************\n"); printf("setting all_quit\n"); pthread_mutex_lock(&all_quit_mutex); img->all_quit = 1; pthread_mutex_unlock(&all_quit_mutex); printf("signalling watch render start thread to wakeup...\n"); pthread_mutex_lock(&img_start_mutex); pthread_cond_signal(&img_start_cond); pthread_mutex_unlock(&img_start_mutex); printf("waiting for watch render start thread to quit...\n"); pthread_join(thread_start, NULL); printf("done\n"); printf("freeing memory\n"); free(img->lines_drawn); free(img->lines_rendered); free(img->arr); free(img); printf("goodbye!\n"); exit(0); } gint gui_idle_draw_cb(image_info* img) { int linesdone; /* timeout.tv_nsec = 500 * 1000; timeout.tv_sec = 0; nanosleep(&timeout, NULL); */ /* pthread_mutex_lock(&lines_done_mutex); if (pthread_cond_timedwait(&line_done_cond, &lines_done_mutex, &timeout) == ETIMEDOUT) { //printf("!"); pthread_mutex_unlock(&lines_done_mutex); return TRUE; } */ pthread_mutex_lock(&img_lines_rendered_mutex); linesdone = img->lines_done; pthread_mutex_unlock(&img_lines_rendered_mutex); int i; int miny = img->min_rendered; int maxy = miny + 16; if (maxy > img->height) maxy = img->height; if (miny == linesdone) return TRUE; if (maxy > linesdone) { maxy = linesdone; } int unrendered = 0; if (miny < maxy) { struct timeval tv; struct timespec timeout; gettimeofday(&tv, NULL); timeout.tv_nsec = tv.tv_usec * 1000 + 500 * 1000; timeout.tv_sec = tv.tv_sec; /* if (pthread_mutex_trylock(&img_lines_rendered_mutex) == EBUSY) return; */ pthread_mutex_lock(&img_lines_rendered_mutex); pthread_cond_timedwait(&lines_rendered_cond, &img_lines_rendered_mutex, &timeout); /* if (pthread_cond_timedwait(&lines_rendered_cond, &img_lines_rendered_mutex, &timeout) == ETIMEDOUT) { //printf("!"); pthread_mutex_unlock(&img_lines_rendered_mutex); return TRUE; } */ for (i = miny; i < maxy; ++i) { char r = img->lines_rendered[i]; if (r == 1) { img->lines_rendered[i] = 2; img->lines_drawn[i] = 1; if (!unrendered) img->min_rendered = i; } else if (!r) unrendered = 1; } pthread_mutex_unlock(&img_lines_rendered_mutex); } miny = img->min_drawn; maxy = miny + 16; if (maxy >= img->height) maxy = img->height; unrendered = 0; int w = img->width; gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gui_pbar), (gfloat)miny / (gfloat)img->height); if (maxy > linesdone) maxy = linesdone; for (i = miny; i < maxy; ++i) { char d = img->lines_drawn[i]; if (d == 1) { img->lines_drawn[i] = 2; if (!unrendered) img->min_drawn = i; int x; guint32* rgb = &img->rgb_data[i * w]; int* data = &img->arr[i * w]; int c; for (x = 0; x < w; ++x) { c = data[x] % 256; rgb[x] = RGB(c, c, c); } gdk_draw_rgb_32_image(drawing_area->window, drawing_area->style->white_gc, 0, i, w, 1, GDK_RGB_DITHER_NONE, (guchar*) ((rgb)), w * 4); } else if (!d) unrendered = 1; } if (i >= img->height) { g_source_remove(img->gui_idle_id); img->gui_idle_id = -1; gtk_widget_hide(gui_pbar); return FALSE; } return TRUE; } void gui_start_render(GtkWidget* widget, gpointer ptr) { image_info* img = (image_info*)ptr; img->min_rendered = 0; img->min_drawn = 0; // printf("************\n" // "GUI signalling to start render...\n" // "************\n"); pthread_mutex_lock(&img_start_mutex); img->start = 1; pthread_cond_signal(&img_start_cond); pthread_mutex_unlock(&img_start_mutex); if (img->gui_idle_id != -1) { g_source_remove(img->gui_idle_id); img->gui_idle_id = -1; } // memset(img->lines_drawn, 0, img->height * sizeof(int)); memset(img->lines_drawn, 0, img->height); gtk_widget_show(gui_pbar); img->gui_idle_id = g_idle_add((GtkFunction)gui_idle_draw_cb, img); } void gui_stop_render(GtkWidget* widget, gpointer ptr) { image_info* img = (image_info*)ptr; // printf("************\n" // "GUI signalling to stop render...\n" // "************\n"); pthread_mutex_lock(&img_stop_mutex); img->stop = 1; pthread_mutex_unlock(&img_stop_mutex); } void* watch_render_start(void* ptr) { image_info* img = (image_info*)ptr; int rc_err; pthread_t render_thread; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); int r; int quit = 0; for(;;) { // printf("watch_render_start: waiting for img_start_cond\n"); pthread_mutex_lock(&img_start_mutex); if (!img->start) pthread_cond_wait(&img_start_cond, &img_start_mutex); img->start = 0; pthread_mutex_unlock(&img_start_mutex); // printf("watch_render_start: recieved img_start_cond\n"); pthread_mutex_lock(&img_rendering_mutex); r = img->rendering; pthread_mutex_unlock(&img_rendering_mutex); // printf("checking if we are rendering... "); if (r) { // printf("Stopping render...\n"); pthread_mutex_lock(&img_stop_mutex); img->stop = 1; pthread_cond_signal(&img_stop_cond); pthread_mutex_unlock(&img_stop_mutex); pthread_join(render_thread, NULL); // printf("render stopped\n"); } // else // printf("no\n"); pthread_mutex_lock(&all_quit_mutex); quit = img->all_quit; pthread_mutex_unlock(&all_quit_mutex); if (quit) { // printf("exiting watch render start thread\n"); pthread_exit(0); } // printf("creating render thread...\n"); rc_err = pthread_create(&render_thread, &attr, &threads_render_create, (void*)img); if (rc_err) pthread_exit(0); } } void* threads_render_create(void* ptr) { Timer timing_info; // printf("initializing render thread\n"); image_info* img = (image_info*)ptr; pthread_mutex_lock(&img_lines_rendered_mutex); // memset(img->lines_rendered, 0, img->height * sizeof(int)); memset(img->lines_rendered, 0, img->height); img->lines_done = 0; pthread_mutex_unlock(&img_lines_rendered_mutex); pthread_mutex_lock(&img_rendering_mutex); img->rendering = 1; pthread_mutex_unlock(&img_rendering_mutex); pthread_mutex_lock(&img_stop_mutex); img->stop = 0; pthread_mutex_unlock(&img_stop_mutex); pthread_mutex_lock(&next_line_mutex); img->next_line = 0; pthread_mutex_unlock(&next_line_mutex); int rc_err, i; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); timer_start(&timing_info); for (i = 0; i < NTHREADS; ++i) { // printf("creating renderer thread #%d...\n", i); rc_err = pthread_create(&img->rend[i], &attr, &render, (void*)img); if (rc_err) { fprintf(stderr, "\nrender thread #%d creation failed: %d\n", i, rc_err); return 0; } } for (i = 0; i < NTHREADS; ++i) { // printf("joining renderer thread #%d...\n", i); pthread_join(img->rend[i], NULL); } timer_stop(&timing_info); printf("render-time %.3fs\n\n", timer_get_elapsed(&timing_info) / (double)1e6); // printf("all renderer threads finished\n"); pthread_mutex_lock(&img_stop_mutex); img->stop = 0; pthread_mutex_unlock(&img_stop_mutex); pthread_mutex_lock(&img_rendering_mutex); img->rendering = 0; pthread_mutex_unlock(&img_rendering_mutex); // printf("at end of threads_render_create\n"); /* pthread_mutex_lock(&lines_done_mutex); if (img->lines_done >= img->height) printf("image complete\n"); else printf("image interuppted\n"); pthread_mutex_unlock(&lines_done_mutex); */ pthread_mutex_lock(&img_start_mutex); img->start = 0; pthread_mutex_unlock(&img_start_mutex); // printf("exiting render thread\n"); pthread_exit(NULL); } void* render(void* ptr) { image_info* img = (image_info*)ptr; int quit = 0; // printf("starting render..\n"); while(next_line(img) && !quit) { pthread_mutex_lock(&img_stop_mutex); quit = img->stop; pthread_mutex_unlock(&img_stop_mutex); pthread_mutex_lock(&all_quit_mutex); quit |= img->all_quit; pthread_mutex_unlock(&all_quit_mutex); } // printf("exiting render thread\n"); pthread_exit(0); } int next_line(image_info* img) { int line; pthread_mutex_lock(&next_line_mutex); line = img->next_line++; pthread_mutex_unlock(&next_line_mutex); if (line >= img->height) return 0; int ix, wz; int img_width = img->width; long double x,y,x2,y2,wre=0,wim=0,wre2=0,wim2=0; long double xmin = img->xmin, xmax = img->xmax, ymax = img->ymax; long double xdiff = xmax - xmin; int depth = img->depth; long double c_im = 0, c_re = 0; y = ymax - (xdiff / (long double)img_width) * (long double)line; y2 = y * y; ix = 0; int mx = 0; int* arr = &img->arr[line * img_width]; while (ix < img_width) { mx += 64; if (mx > img_width) mx = img_width; for (; ix < mx; ++ix) { x = ((long double)ix / (long double)img_width) * xdiff + xmin; x2 = x * x; wre = c_re = x; wim = c_im = y; wre2 = x2; wim2 = y2; for (wz = 0; wz < depth; ++wz) { wim = 2.0 * wre * wim + c_im; wre = wre2 - wim2 + c_re; wim2 = wim * wim; wre2 = wre * wre; if (wim2 + wre2 > 4.0F) break; } if (wz == depth + 1) wz = 0; *arr++ = wz; } pthread_mutex_lock(&img_stop_mutex); if (img->stop) { pthread_mutex_unlock(&img_stop_mutex); return 0; } pthread_mutex_unlock(&img_stop_mutex); } // printf("line %d complete\n", line); pthread_mutex_lock(&img_lines_rendered_mutex); img->lines_rendered[line] = 1; pthread_cond_signal(&lines_rendered_cond); img->lines_done++; if (img->lines_done == img->height) { pthread_mutex_unlock(&img_lines_rendered_mutex); return 0; } pthread_mutex_unlock(&img_lines_rendered_mutex); return 1; } static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) { return FALSE; } static void destroy(GtkWidget *widget, gpointer data) { gtk_main_quit (); }
_______________________________________________ NetBehaviour mailing list NetBehaviour@netbehaviour.org http://www.netbehaviour.org/mailman/listinfo/netbehaviour