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 [email protected] http://www.netbehaviour.org/mailman/listinfo/netbehaviour
