The Computer Language
Benchmarks Game

thread-ring C gcc #3 program

source code

/* The Computer Language Benchmarks Game
 * http://benchmarksgame.alioth.debian.org/

   contributed by Alex Burlyga
*/

#define _GNU_SOURCE
#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>

#define NUMBER_OF_THREADS 503

pthread_mutex_t cv_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv_main = PTHREAD_COND_INITIALIZER;
pthread_cond_t *cvs = NULL;
uint32_t token = 0;
uint32_t token_count = 1000;
uint32_t threads_started = 0;
uint32_t number_of_cpus = 0;

void *thread_function(void *arg) {
    uint32_t thread_num = *(uint32_t *)arg;
    uint32_t next_thread_num = (thread_num + 1) % NUMBER_OF_THREADS;
    cpu_set_t cpu_mask;

    CPU_ZERO(&cpu_mask);
    CPU_SET(0, &cpu_mask);
    pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpu_mask);

    pthread_mutex_lock(&cv_mutex);
    while (1) {
        threads_started++;
        pthread_cond_signal(&cv_main);
        pthread_cond_wait(cvs+thread_num, &cv_mutex);
        token++;
        if (token == token_count + 1) {
            printf("%d\n", thread_num + 1);
            token++;
            pthread_cond_signal(cvs+next_thread_num);
            pthread_mutex_unlock(&cv_mutex);
            break;
        } else if (token > token_count + 1) {
            pthread_cond_signal(cvs+next_thread_num);
            pthread_mutex_unlock(&cv_mutex);
            break;
        }
        pthread_cond_signal(cvs+next_thread_num);
    }

    pthread_exit(NULL);
}

int
main(int argc, char **argv) {
    int errno = 0;
    pthread_t *threads = NULL;
    uint32_t *thread_args = NULL;

    if (argc > 1) {
        token_count = strtol(argv[1], NULL, 0);
    }

    number_of_cpus = sysconf(_SC_NPROCESSORS_CONF);

    threads = (pthread_t *)malloc(sizeof(pthread_t)*NUMBER_OF_THREADS);
    if (threads == NULL) {
        perror("pthread_t array malloc");
        exit(1);
    }
    memset(threads, 0, sizeof(pthread_t)*NUMBER_OF_THREADS);

    thread_args = (uint32_t *)malloc(sizeof(uint32_t)*NUMBER_OF_THREADS);
    if (thread_args == NULL) {
        perror("thread_args array malloc");
        exit(1);
    }
    memset(thread_args, 0, sizeof(uint32_t)*NUMBER_OF_THREADS);

    cvs = (pthread_cond_t *)malloc(sizeof(pthread_cond_t)*NUMBER_OF_THREADS);
    if (cvs == NULL) {
        perror("cvs array malloc");
        exit(1);
    }

    pthread_mutex_lock(&cv_mutex);
    for (uint32_t i = 0; i < NUMBER_OF_THREADS; i++) {
        *(thread_args + i) = i;
        errno = pthread_cond_init(cvs+i, NULL);
        if (errno) {
            perror("pthread_cond_init");
            exit(1);
        }

        errno = pthread_create(threads+i, NULL, thread_function, (void *)(thread_args + i));
        if (errno) {
            perror("pthread_create");
            exit(1);
        }
    }

    while(threads_started < NUMBER_OF_THREADS) {
        pthread_cond_wait(&cv_main, &cv_mutex);
    }
    pthread_cond_signal(cvs);
    pthread_mutex_unlock(&cv_mutex);

    for (int i = 0; i < NUMBER_OF_THREADS; i++) {
        pthread_join(*(threads + i), NULL);
    }

    free(cvs);
    free(thread_args);
    free(threads);
    pthread_exit(NULL);
}
    

notes, command-line, and program output

NOTES:
64-bit Ubuntu quad core
gcc (Ubuntu 7.2.0-8ubuntu3) 7.2.0


Sat, 28 Oct 2017 18:46:44 GMT

MAKE:
/usr/bin/gcc -pipe -Wall -O3 -fomit-frame-pointer -march=native -pthread threadring.gcc-3.c -o threadring.gcc-3.gcc_run 
rm threadring.gcc-3.c

0.14s to complete and log all make actions

COMMAND LINE:
./threadring.gcc-3.gcc_run 50000000

PROGRAM OUTPUT:
292