Skip to content

Instantly share code, notes, and snippets.

@OliverUv
Created May 15, 2013 23:36
Show Gist options
  • Select an option

  • Save OliverUv/5588300 to your computer and use it in GitHub Desktop.

Select an option

Save OliverUv/5588300 to your computer and use it in GitHub Desktop.
/*
File: blurfilter_pthread.c
Implementation of blurfilter function using pthreads.
*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "blurfilter.h"
#include "ppmio.h"
/* Global variables shared by threads. */
static pthread_t *threads;
static pthread_attr_t t_attr;
static pthread_barrier_t barrier;
static const double *weights_g;
static pixel *tmp_g;
static pixel *src_g;
static int radius_g;
static int xsize_g, ysize_g;
struct blur_args {
int starting_row;
int num_rows;
};
pixel* pix(pixel* image, const int xx, const int yy, const int xsize)
{
register int off = xsize*yy + xx;
#ifdef DBG
if(off >= MAX_PIXELS) {
fprintf(stderr, "\n Terribly wrong: %d %d %d\n",xx,yy,xsize);
}
#endif
return (image + off);
}
static void *do_blur(void *arguments)
{
struct blur_args* arg = (struct blur_args*) arguments;
int wi, x, y, x2, y2;
int r, g, b, n, wc;
int start = arg->starting_row;
int end = arg->num_rows + arg->starting_row;
for (y = start; y < end; y++) {
for (x=0; x<xsize_g; x++) {
r = weights_g[0] * pix(src_g, x, y, xsize_g)->r;
g = weights_g[0] * pix(src_g, x, y, xsize_g)->g;
b = weights_g[0] * pix(src_g, x, y, xsize_g)->b;
n = weights_g[0];
for ( wi=1; wi <= radius_g; wi++) {
wc = weights_g[wi];
x2 = x - wi;
if(x2 >= 0) {
r += wc * pix(src_g, x2, y, xsize_g)->r;
g += wc * pix(src_g, x2, y, xsize_g)->g;
b += wc * pix(src_g, x2, y, xsize_g)->b;
n += wc;
}
x2 = x + wi;
if(x2 < xsize_g) {
r += wc * pix(src_g, x2, y, xsize_g)->r;
g += wc * pix(src_g, x2, y, xsize_g)->g;
b += wc * pix(src_g, x2, y, xsize_g)->b;
n += wc;
}
}
pix(tmp_g,x,y, xsize_g)->r = r/n;
pix(tmp_g,x,y, xsize_g)->g = g/n;
pix(tmp_g,x,y, xsize_g)->b = b/n;
}
}
// Wait for other threads to finish horizontal bluring.
pthread_barrier_wait(&barrier);
for (y = start; y < end; y++) {
for (x=0; x<xsize_g; x++) {
r = weights_g[0] * pix(tmp_g, x, y, xsize_g)->r;
g = weights_g[0] * pix(tmp_g, x, y, xsize_g)->g;
b = weights_g[0] * pix(tmp_g, x, y, xsize_g)->b;
n = weights_g[0];
for (wi=1; wi <= radius_g; wi++) {
wc = weights_g[wi];
y2 = y - wi;
if(y2 >= 0) {
r += wc * pix(tmp_g, x, y2, xsize_g)->r;
g += wc * pix(tmp_g, x, y2, xsize_g)->g;
b += wc * pix(tmp_g, x, y2, xsize_g)->b;
n += wc;
}
y2 = y + wi;
if(y2 < end) {
r += wc * pix(tmp_g, x, y2, xsize_g)->r;
g += wc * pix(tmp_g, x, y2, xsize_g)->g;
b += wc * pix(tmp_g, x, y2, xsize_g)->b;
n += wc;
}
}
pix(src_g,x,y, xsize_g)->r = r/n;
pix(src_g,x,y, xsize_g)->g = g/n;
pix(src_g,x,y, xsize_g)->b = b/n;
}
}
pthread_exit(NULL);
}
void define_workloads(int ysize, int xsize, int num_threads, struct blur_args* args)
{
// Calculate number of pixels per thread
int i;
int rows_to_modify_per_thread = ysize / num_threads;
for (i = 0; i < num_threads; ++i) {
args[i].num_rows = rows_to_modify_per_thread;
}
int rest = ysize % num_threads;
args[num_threads - 1].num_rows += rest;
// Calculate displacement per thread
int sum_rows = 0;
for (i = 0; i < num_threads; ++i)
{
args[i].starting_row = sum_rows;
sum_rows += args[i].num_rows;
}
}
void blurfilter(const int xsize, const int ysize, pixel* src,
const int radius, const double *w)
{
int num_threads, i;
weights_g = w;
radius_g = radius;
xsize_g = xsize;
ysize_g = ysize;
src_g = src;
tmp_g = malloc(xsize * ysize * sizeof(*tmp_g));
char *num_threads_env = getenv("NUM_THREADS");
if (num_threads_env)
num_threads = atoi(num_threads_env);
else
num_threads = 16;
threads = malloc(num_threads * sizeof(*threads));
pthread_attr_init(&t_attr);
pthread_barrier_init(&barrier, NULL, num_threads);
pthread_attr_setdetachstate(&t_attr, PTHREAD_CREATE_JOINABLE);
struct blur_args args[num_threads];
define_workloads(ysize, xsize, num_threads, args);
// Launch first pass
for (i = 0; i < num_threads; ++i)
{
pthread_create(&threads[i], &t_attr, do_blur, (void *) &args[i]);
// TODO check for errors when return value != 0
}
// Ensure all threads have reached this point before progressing.
void *status;
for (i = 0; i < num_threads; ++i)
{
pthread_join(threads[i], &status);
// TODO check for errors when return value != 0
}
pthread_attr_destroy(&t_attr);
pthread_barrier_destroy(&barrier);
free(tmp_g);
free(threads);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment