浏览代码

mandelbrot: restart of multi-threaded work

Douglas A 4 年之前
父节点
当前提交
084d693939
共有 5 个文件被更改,包括 271 次插入196 次删除
  1. 4 1
      mandelbrot/Makefile
  2. 2 2
      mandelbrot/config.h
  3. 149 193
      mandelbrot/mandelbrot.c
  4. 42 0
      mandelbrot/mandelbrot.h
  5. 74 0
      mandelbrot/queue.c

+ 4 - 1
mandelbrot/Makefile

@@ -2,7 +2,7 @@ CC=/usr/bin/gcc
 CFLAGS=-g -Werror -D _DEFAULT_SOURCE -O0 -D_XOPEN_SOURCE=600 -pthread -pedantic -pedantic-errors -fno-fast-math -fno-builtin -m64 -std=iso9899:1999 -I${PWD} -I${PWD}/../libpng 
 OUT=bin
 OBJ=$(OUT)/obj
-OBJS=$(OBJ)/mandelbrot.o $(OBJ)/img.o
+OBJS=$(OBJ)/mandelbrot.o $(OBJ)/img.o  $(OBJ)/queue.o   
 
 
 all: pre bin/mandelbrot
@@ -16,6 +16,9 @@ bin/obj/mandelbrot.o: mandelbrot.c config.h
 bin/obj/img.o: ../libpng/img.c
 	$(CC) $(CFLAGS) -c ../libpng/img.c -o $(OBJ)/img.o -lpng
 
+bin/obj/queue.o: queue.c
+	$(CC) $(CFLAGS) -c queue.c -o $(OBJ)/queue.o -pthread
+
 pre:
 	mkdir -p bin/obj
 

+ 2 - 2
mandelbrot/config.h

@@ -1,5 +1,5 @@
-#define BAIL_OUT 16777215
-#define MAX_ITER 2147483647
+#define BAIL_OUT 32
+#define MAX_ITER 64
 
 #define WIDTH 1024
 #define HEIGHT 1024

+ 149 - 193
mandelbrot/mandelbrot.c

@@ -1,226 +1,182 @@
-#include <stdio.h>
-#include <pthread.h>
-#include <semaphore.h>
-#include <unistd.h>
-
-
-#include "../libpng/img.h"
-#include "config.h"
-
-typedef struct mandel_field_t {
-    int h, w;
-    int *arr;
-    pthread_mutex_t mut;
-} mandel_field_t;
-
-typedef struct mandel_t {
-    int x, y;
-    int bail_out;
-    int max_iter;
-    mandel_field_t field;
-} mandel_t;
-
-typedef struct inner {
-    pthread_mutex_t mut;
-} inner;
-
-typedef struct buffer {
-    sem_t empty;
-    sem_t full;
-    pthread_mutex_t mut;
-    int pos;
-    mandel_t **pix;
-    inner *in;
-} buffer;
-
-
+#include "mandelbrot.h"
 
 double map(int value, int min, int max, int map_min, int map_max)
 {
-    double R = (double) (map_max - map_min) / (double) (max - min);
-    double y = map_min + (value * R) + R;
-    return y;
+	double R = (double) (map_max - map_min) / (double) (max - min);
+	double y = map_min + (value * R) + R;
+	return y;
 }
 
-
 int mandelbrot_pix(double x, double y, int bail_out, int max_iter)
 {
-    int k;
-    double real, imaginary, x2, y2;
-
-    x2 = x;
-    y2 = y;
-
-    // iterate a^2 - b^2 + 2ab
-    for (k = 0; k < max_iter; k++) {
-	// a^2 - b^2
-	real = x * x - y * y;
-	// 2ab
-	imaginary = 2 * x * y;
-
-	// x = real + c
-	x = real + x2;
-	// y = imaginary + c
-	y = imaginary +y2;
-
-	if ((x * x + y * y) > bail_out) {
-	    return k;
-	}
-    }
-    return max_iter;
-}
-
-void init_buffer(buffer * buf)
-{
-    sem_init(&buf->empty, 0, 0);
-    sem_init(&buf->full, 0, BUFFER_SIZE);
-    buf->in = malloc(sizeof(inner));
-    buf->pos = 0;
-    buf->pix = malloc(sizeof(mandel_t) * BUFFER_SIZE);
-
-    for (int i = 0; i < BUFFER_SIZE; i++) {
-	buf->pix[i] = NULL;
-    }
-}
-
-void mandel_field_setXY(mandel_field_t m, int x, int y, int value)
-{
-    pthread_mutex_lock(&m.mut);
-    m.arr[x * m.h + y] = value;
-    pthread_mutex_unlock(&m.mut);
-}
-
-void *mandel_consumer(void *buff)
-{
-    buffer *buf = (buffer *) buff;
-    mandel_t *pix;
-    int count = 0;
-    double xPrime, yPrime;
-
-    while (1) {
-
-	int tw = sem_trywait(&buf->empty);
-	if (tw == 0) {
-	    pthread_mutex_lock(&buf->mut);
-
-	    buf->pos = buf->pos - 1;
-	    pix = buf->pix[buf->pos];
-	    count++;
-	    sem_post(&buf->full);
-
-
-	    xPrime = map(pix->x, 0, pix->field.w, -2, 2);
-	    yPrime = map(pix->y, 0, pix->field.h, -2, 2);
-
-	    int k = mandelbrot_pix(xPrime, yPrime, pix->bail_out,
-				   pix->max_iter);
-	    mandel_field_setXY(pix->field, pix->x, pix->y, k);
-	    pthread_mutex_unlock(&buf->mut);
-	} else {
-	    int rc = pthread_mutex_trylock(&buf->in->mut);
-	    if (rc == 0) {
-		printf("\ngot lock");
-		pthread_mutex_unlock(&buf->in->mut);
-		pthread_exit(NULL);
-	    }
+	int k;
+	double real, imaginary, x2, y2;
+
+	x2 = x;
+	y2 = y;
+
+	// iterate a^2 - b^2 + 2ab
+	for (k = 0; k < max_iter; k++) {
+		// a^2 - b^2
+		real = x * x - y * y;
+		// 2ab
+		imaginary = 2 * x * y;
+
+		// x = real + c
+		x = real + x2;
+		// y = imaginary + c
+		y = imaginary +y2;
+
+		if ((x * x + y * y) > bail_out) {
+			return k;
+		}
 	}
-    }
+	return max_iter;
 }
 
 void mandelbrot(int *field, int w, int h, int bail_out, int max_iter,
 		int thread_count)
 {
-    double xPrime, yPrime;
-    int x, y, k;
 
-    buffer *buf;
-    buf = malloc(sizeof(buffer));
-    init_buffer(buf);
+	for (int i = 0; i < w; i++) {
+		for (int j = 0; j < h; j++) {
+			double x = map(i, 0, w, -1, 1);
+			double y = map(j, 0, h, -1, 1);
 
-    pthread_t t[thread_count];
-    pthread_attr_t attr;
+			int k = mandelbrot_pix(x, y, BAIL_OUT, MAX_ITER);
+			fprintf(stdout, "\nComputing %d %d = %d", i, j, k);
+			field[i + j * h] = k;
+		}
+	}
 
-    pthread_attr_init(&attr);
+}
 
-    pthread_mutex_lock(&buf->in->mut);
-    for (int i = 0; i < thread_count; i++) {
-	pthread_create(&t[i], &attr, mandel_consumer, buf);
-    }
+void *produce(void *b)
+{
+	mandel_buf_t *buf;
+	mandel_t *m;
 
-    for (int i = 0; i < w; i++) {
-	for (int j = 0; j < h; j++) {
-	    sem_wait(&buf->full);
-	    pthread_mutex_lock(&buf->mut);
+	double x;
+	double y;
 
+	buf = (mandel_buf_t *) b;
 
-	    buf->pix[buf->pos] = malloc(sizeof(mandel_t));
-	    buf->pix[buf->pos]->x = i;
-	    buf->pix[buf->pos]->y = j;
-	    buf->pix[buf->pos]->bail_out = bail_out;
-	    buf->pix[buf->pos]->max_iter = max_iter;
-	    buf->pix[buf->pos]->field.arr = field;
-	    buf->pix[buf->pos]->field.h = h;
-	    buf->pix[buf->pos]->field.w = w;
-	    buf->pos += 1;
+	for (int i = 0; i < buf->prop.width; i++) {
+		for (int j = 0; j < buf->prop.height; j++) {
 
-	    sem_post(&buf->empty);
-	    pthread_mutex_unlock(&buf->mut);
+			m = malloc(sizeof(mandel_t));
+			m->x = i;
+			m->y = j;
+			enqueue(buf->q, m, buf->lock);
+		}
 	}
-    }
-    pthread_mutex_unlock(&buf->in->mut);
-    printf("Finished filling the buffer");
-
-    for (int i = 0; i < thread_count; i++) {
-	pthread_join(t[i], NULL);
-    }
+}
 
-    free(buf->in);
-    free(buf->pix);
-    free(buf);
+void *consume(void *b)
+{
+	mandel_buf_t *buf;
+	mandel_t *m;
+	double x, y;
+	int k, i;
+
+	buf = (mandel_buf_t *) b;
+
+
+	/* This will not work on a multi-consumer program */
+	while (i < buf->prop.width * buf->prop.height) {
+		if (!is_empty(buf->q)) {
+			m = dequeue(buf->q, buf->lock);
+			x = map(m->x, 0, buf->prop.width, -1, 1);
+			y = map(m->y, 0, buf->prop.height, -1, 1);
+			//fprintf(stdout, "\nSending %d %d", m->x, m->y, k);
+
+			k = mandelbrot_pix(x, y, buf->prop.bail_out,
+					buf->prop.max_iter);
+			buf->result_field[m->y + m->x * buf->prop.height] = k;
+			free(m);
+			i++;
+		}
+	}
 }
 
 int main(int argc, char **argv)
 {
 
-    int *pix_field;
-
-    pix_field = malloc(WIDTH * HEIGHT * sizeof(int));
-
-    printf
-	("WIDTH: %d\nHEIGHT %d\nBAIL OUT %d\nMAX ITER %d\nTHREAD COUNT %d",
-	 WIDTH, HEIGHT, BAIL_OUT, MAX_ITER, THREAD_COUNT);
-
-
-    mandelbrot(pix_field, WIDTH, HEIGHT, BAIL_OUT, MAX_ITER, THREAD_COUNT);
-
-    pix_row rows[WIDTH];
-    pix p;
-
-    char filename[30];
-    image img;
-    p.r = 200;
-    p.g = 200;
-    p.b = 200;
-
-    for (int i = 0; i < WIDTH; i++) {
-	rows[i].p = malloc(HEIGHT * sizeof(pix));
-	for (int j = 0; j < HEIGHT; j++) {
-	    p.r = map(pix_field[i * HEIGHT + j], 0, MAX_ITER, 0, 255);
-	    p.g = map(pix_field[i * HEIGHT + j], 0, MAX_ITER, 0, 255);
-	    p.b = map(pix_field[i * HEIGHT + j], 0, MAX_ITER, 0, 255);
-	    rows[i].p[j] = p;
+	pthread_t consumer;
+	pthread_t producer;
+	pthread_attr_t attr;
+	pthread_mutex_t lock;
+
+	printf
+	    ("WIDTH: %d\nHEIGHT %d\nBAIL OUT %d\nMAX ITER %d\nTHREAD COUNT %d",
+	     WIDTH, HEIGHT, BAIL_OUT, MAX_ITER, THREAD_COUNT);
+
+	pthread_attr_init(&attr);
+
+	/* Define current mandelbrot set properties */
+	mandel_prop_t prop;
+	prop.bail_out = BAIL_OUT;
+	prop.max_iter = MAX_ITER;
+	prop.height = HEIGHT;
+	prop.width = WIDTH;
+
+	/* Initialize the buffer for threads to work with */
+	mandel_buf_t buf;
+	buf.prop = prop;
+	queue_t *queue;
+	queue = initialize_queue();
+	pthread_mutex_init(&lock, NULL);
+	buf.lock = &lock;
+	buf.result_field = malloc(sizeof(int) * WIDTH * HEIGHT);
+
+	buf.q = queue;
+
+	/* Create and start threads */
+	pthread_create(&producer, &attr, produce, &buf);
+	pthread_create(&consumer, &attr, consume, &buf);
+
+
+
+	pthread_join(producer, NULL);
+	printf("\nFinished producer!");
+	pthread_join(consumer, NULL);
+	printf("\nFinished consumer!");
+
+	/* Create the png image with the result buffer */
+	pix_row rows[WIDTH];
+	pix p;
+
+	char filename[30];
+	image img;
+	p.r = 200;
+	p.g = 200;
+	p.b = 200;
+
+	for (int i = 0; i < WIDTH; i++) {
+		rows[i].p = malloc(HEIGHT * sizeof(pix));
+		for (int j = 0; j < HEIGHT; j++) {
+			p.r =
+			    map(buf.result_field[i * HEIGHT + j], 0,
+				MAX_ITER, 0, 255);
+			p.g =
+			    map(buf.result_field[i * HEIGHT + j], 0,
+				MAX_ITER, 0, 255);
+			p.b =
+			    map(buf.result_field[i * HEIGHT + j], 0,
+				MAX_ITER, 0, 255);
+			rows[i].p[j] = p;
+		}
 	}
-    }
-    sprintf(filename, "mandel.png");
-    img = initialize_png("mandelbrot", filename, WIDTH, HEIGHT);
-    write_image(&img, rows);
-    finish_image(&img);
-    for (int i = 0; i < WIDTH; i++) {
+	sprintf(filename, "mandel.png");
+	img = initialize_png("mandelbrot", filename, WIDTH, HEIGHT);
+	write_image(&img, rows);
+	finish_image(&img);
+	for (int i = 0; i < WIDTH; i++) {
 
-	free(rows[i].p);
-    }
+		free(rows[i].p);
+	}
 
-    free(pix_field);
+	free(buf.result_field);
 
-    return (0);
+	return (0);
 }

+ 42 - 0
mandelbrot/mandelbrot.h

@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <unistd.h>
+
+#include "../libpng/img.h"
+#include "config.h"
+
+typedef struct queue {
+	struct queue_node_t *head;
+	struct queue_node_t *tail;
+} queue_t;
+
+typedef struct mandel_t {
+	int x;
+	int y;
+} mandel_t;
+
+struct queue_node_t {
+	mandel_t *node;
+	struct queue_node_t *next;
+};
+
+typedef struct mandel_prop_t {
+	int width;
+	int height;
+	int bail_out;
+	int max_iter;
+} mandel_prop_t;
+
+typedef struct mandel_buf_t {
+	queue_t *q;
+	int *result_field;
+	mandel_prop_t prop;
+	pthread_mutex_t *lock;
+} mandel_buf_t;
+
+queue_t *initialize_queue();
+void enqueue(queue_t * q, mandel_t * w, pthread_mutex_t * lock);
+mandel_t *dequeue(queue_t * q, pthread_mutex_t * lock);
+void destroy_queue(queue_t * q);
+int is_empty(queue_t * q);

+ 74 - 0
mandelbrot/queue.c

@@ -0,0 +1,74 @@
+#include "mandelbrot.h"
+
+queue_t *initialize_queue()
+{
+	queue_t *q;
+
+	q = (queue_t *) malloc(sizeof(queue_t *));
+
+	return q;
+}
+
+void enqueue(queue_t * q, mandel_t * w, pthread_mutex_t * lock)
+{
+	struct queue_node_t *aux;
+
+	pthread_mutex_lock(lock);
+
+	if (q->head == NULL) {
+		q->head =
+		    (struct queue_node_t *)
+		    malloc(sizeof(struct queue_node_t *));
+		q->head->next = NULL;
+		q->head->node = w;
+		q->tail = q->head;
+	} else {
+		aux =
+		    (struct queue_node_t *)
+		    malloc(sizeof(struct queue_node_t *));
+		aux->next = NULL;
+		aux->node = w;
+		q->tail->next = aux;
+		q->tail = aux;
+	}
+
+	pthread_mutex_unlock(lock);
+}
+
+mandel_t *dequeue(queue_t * q, pthread_mutex_t * lock)
+{
+	struct queue_node_t *aux;
+	mandel_t *ret_val;
+
+	if (q->head != NULL) {
+		pthread_mutex_lock(lock);
+		ret_val = q->head->node;
+		aux = q->head;
+		q->head = q->head->next;
+		pthread_mutex_unlock(lock);
+		free(aux);
+		return (ret_val);
+	}
+	return NULL;
+
+}
+
+int is_empty(queue_t * q)
+{
+	return (q->head == NULL);
+}
+
+void destroy_queue(queue_t * q)
+{
+	struct queue_node_t *aux, *next;
+
+	aux = q->head;
+
+	while (aux != NULL) {
+		next = aux->next;
+		free(aux);
+		if (next != NULL)
+			aux = next;
+	}
+	free(q);
+}