#define _XOPEN_SOURCE 600 /* pthread_barrier_* */
#include <stdio.h> /* printf(), puts() */
#include <stdlib.h> /* exit() */
#include <unistd.h> /* sleep() */
#include <complex.h> /* complex numbers */
#include <pthread.h> /* threads */
#define STR_VAL(x) STR(x)
#define STR(x) #x
#define MAX_THREADS 1024
#define new(x) malloc(sizeof(x))
struct {
pthread_mutex_t lock;
struct coordinates { complex double z, c; } *coordinates;
double escape_count;
} result;
pthread_barrier_t complete;
__attribute__((noreturn))
static void usage (char *myself) {
printf("Usage: %s [threads]\n", myself);
puts("threads must be between 1 and " STR_VAL(MAX_THREADS) );
exit(-1);
}
#define tprintf(x, ...) {\
printf("[%08lX] " x, (unsigned long)pthread_self(), __VA_ARGS__);\
fflush(stdout);\
}
#define tputs(x) {\
printf("[%08lX] " x "\n", (unsigned long)pthread_self());\
fflush(stdout);\
}
static inline void *iterate (void *where) {
struct coordinates *coordinates = (struct coordinates *)where;
tprintf("Z = %f+%fi, C = %f+%fi\n",
creal(coordinates->z), cimag(coordinates->z),
creal(coordinates->c), cimag(coordinates->c)
);
sleep(1 + rand() % 2);
double count = (double)rand() / RAND_MAX;
pthread_mutex_lock(&result.lock);
result.coordinates = coordinates;
result.escape_count = count;
pthread_barrier_wait(&complete);
return NULL;
}
static inline struct coordinates *next_coordinates (void) {
struct coordinates *coordinates = new(struct coordinates);
coordinates->z = (double)rand() / RAND_MAX + (double)rand() / RAND_MAX * I;
coordinates->c = (double)rand() / RAND_MAX + (double)rand() / RAND_MAX * I;
return coordinates;
}
static inline void cleanup (void) {
pthread_barrier_wait(&complete);
printf("[DISPATCH] Z = %f+%fi, C = %f+%fi, escape_count = %f\n",
creal(result.coordinates->z),
cimag(result.coordinates->z),
creal(result.coordinates->c),
cimag(result.coordinates->c),
result.escape_count
);
free(result.coordinates);
pthread_mutex_unlock(&result.lock);
}
pthread_attr_t thread_attributes;
static inline void spawn (void) {
pthread_t tmp;
pthread_create(&tmp, &thread_attributes, &iterate, next_coordinates());
}
static inline void dispatch (unsigned threads) {
pthread_barrier_init(&complete, NULL, 2);
pthread_attr_init(&thread_attributes);
pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_DETACHED);
for (unsigned i = 0; i < threads; i++) spawn();
/* while unassigned work */
for (unsigned i = 0; i < threads; i++) { cleanup(); spawn(); }
for (unsigned i = 0; i < threads; i++) cleanup();
pthread_attr_destroy(&thread_attributes);
pthread_barrier_destroy(&complete);
}
int main (int argc, char **argv) {
if (argc < 2) usage(argv[0]);
unsigned threads = atoi(argv[1]);
if (MAX_THREADS < threads || 0 >= threads) usage(argv[0]);
printf("running %d concurrent threads\n", threads);
fflush(stdout);
dispatch(threads);
return 0;
}