/*
Simple example of dividing a task between `n' threads.
Compile like:
$ gcc -O3 -pthread thread_sum.c -o thread_sum
One thread takes 10 seconds:
$ time ./thread_sum 1 10000000000
Creating 1 threads to sum the first 10000000000 integers
Each thread will sum 10000000000 integers
Thread summing integers 0 to 10000000000 finished sum is 49999999990067863552
Combined sum of integers 0 to 10000000000 is 49999999990067863552
real 0m11.924s
user 0m11.919s
sys 0m0.004s
$
Four threads runs 4x as fast on a machine with 4 cores:
$ time ./thread_sum 4 10000000000
Creating 4 threads to sum the first 10000000000 integers
Each thread will sum 2500000000 integers
Thread summing integers 2500000000 to 5000000000 finished sum is 9374999997502005248
Thread summing integers 7500000000 to 10000000000 finished sum is 21874999997502087168
Thread summing integers 5000000000 to 7500000000 finished sum is 15624999997500696576
Thread summing integers 0 to 2500000000 finished sum is 3124999997567081472
Combined sum of integers 0 to 10000000000 is 49999999990071869440
real 0m3.154s
user 0m12.563s
sys 0m0.004s
$
Note the result is inexact, because we use values can't be exactly
represented as double and exact value printed depends on how many
threads we use - because we break up the computation differently
depending on the number of threads.
*/
#include
#include
#include
#include
struct job {
long start, finish;
double sum;
};
void *run_thread (void *argument)
{
struct job *j = argument;
long start = j->start;
long finish = j->finish;
double sum = 0;
for (long i = start; i < finish; i++) {
sum += i;
}
j->sum = sum;
printf (
"Thread summing integers %10lu to %11lu finished sum is %20.0f\n",
start, finish, sum);
return NULL;
}
int
main (int argc, char *argv[])
{
if (argc != 3) {
fprintf (
stderr,
"Usage: %s \n",
argv[0]);
return 1;
}
int n_threads = strtol (argv[1], NULL, 0);
assert (0 < n_threads && n_threads < 1000);
long integers_to_sum = strtol (argv[2], NULL, 0);
assert (0 < integers_to_sum);
long integers_per_thread = (integers_to_sum - 1) / n_threads + 1;
printf (
"Creating %d threads to sum the first %lu integers\n"
"Each thread will sum %lu integers\n",
n_threads, integers_to_sum, integers_per_thread);
pthread_t thread_id[n_threads];
struct job jobs[n_threads];
for (int i = 0; i < n_threads; i++) {
jobs[i].start = i * integers_per_thread;
jobs[i].finish = jobs[i].start + integers_per_thread;
if (jobs[i].finish > integers_to_sum) {
jobs[i].finish = integers_to_sum;
}
// create a thread which will sum integers_per_thread integers
pthread_create (&thread_id[i], NULL, run_thread, &jobs[i]);
}
// Wait for threads to finish, then add results for an overall sum.
double overall_sum = 0;
for (int i = 0; i < n_threads; i++) {
pthread_join (thread_id[i], NULL);
overall_sum += jobs[i].sum;
}
printf (
"\nCombined sum of integers 0 to %lu is %.0f\n",
integers_to_sum, overall_sum);
return 0;
}