Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_parallel_for.c

n_parallel_for(): a loop over a range on several cores

n_parallel_for(): a loop over a range on several cores

Author
Castagnier Mickael
Version
1.0
Date
24/09/2026

Fills an array in parallel and checks every item was written exactly once, whatever the slicing; that a small range runs on the caller alone; that an empty range does nothing; and that two parallel loops started at once from two threads, as workers of a pool do, both finish right while sharing one budget of cores.

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nilorea/n_log.h"
static int failures = 0;
static void expect_true(const char* what, int ok) {
if (!ok) {
n_log(LOG_ERR, "FAIL: %s", what);
}
}
static void bump(size_t begin, size_t end, void* user) {
int* items = (int*)user;
size_t i = 0;
for (i = begin; i < end; i++) items[i]++;
}
static void* nested(void* arg) {
n_parallel_for(0, 1000000, 1000, bump, arg);
return NULL;
}
static int all_ones(const int* items, size_t count) {
size_t i = 0;
for (i = 0; i < count; i++)
if (items[i] != 1) return 0;
return 1;
}
int main(void) {
int* a = NULL;
int* b = NULL;
pthread_t other;
int slices = 0;
a = calloc(1000000, sizeof(int));
b = calloc(1000000, sizeof(int));
if (!a || !b) return 1;
slices = n_parallel_for(0, 1000000, 1000, bump, a);
n_log(LOG_NOTICE, "ex_parallel_for: a million items in %d slice(s) on %ld core(s)", slices, get_nb_cpu_cores());
expect_true("every item written exactly once", all_ones(a, 1000000));
expect_true("more than one slice on a machine with more than one core",
get_nb_cpu_cores() < 2 || slices > 1);
memset(a, 0, 1000000 * sizeof(int));
expect_true("a range under two grains runs as one slice", n_parallel_for(0, 1500, 1000, bump, a) == 1);
expect_true("and does all of it", all_ones(a, 1500));
expect_true("an empty range does nothing", n_parallel_for(10, 10, 1, bump, a) == 0);
expect_true("a NULL function does nothing", n_parallel_for(0, 10, 1, NULL, a) == 0);
/* Two at once, sharing the budget. */
memset(a, 0, 1000000 * sizeof(int));
if (pthread_create(&other, NULL, nested, b) != 0) return 1;
n_parallel_for(0, 1000000, 1000, bump, a);
pthread_join(other, NULL);
expect_true("two loops at once both finish right", all_ones(a, 1000000) && all_ones(b, 1000000));
free(a);
free(b);
n_log(LOG_NOTICE, "ex_parallel_for: %s", failures ? "FAILED" : "ok");
return failures ? 1 : 0;
}
static int failures
Definition ex_atlas.c:51
int main(void)
Definition ex_atlas.c:117
static void expect_true(const char *label, int cond)
Definition ex_atlas.c:53
static void * nested(void *arg)
a loop run from another thread, as a pool worker would
static void bump(size_t begin, size_t end, void *user)
add one to each item of the slice, so a slice done twice shows as a 2
static int all_ones(const int *items, size_t count)
every item is exactly one
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:113
#define LOG_ERR
error conditions
Definition n_log.h:100
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL ).
Definition n_log.c:123
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:104
int n_parallel_for(size_t begin, size_t end, size_t grain, N_PARALLEL_FN fn, void *user)
Run a loop over a range on several cores, and return when all of it is done.
long int get_nb_cpu_cores()
get number of core of current system
Common headers and low-level functions & define.
Generic log system.
Thread pool declaration.