Skip to content

Instantly share code, notes, and snippets.

@szaydel
Last active November 29, 2021 13:50
Show Gist options
  • Select an option

  • Save szaydel/1f2a02cfb80f3e67d97f10926cc7a1fb to your computer and use it in GitHub Desktop.

Select an option

Save szaydel/1f2a02cfb80f3e67d97f10926cc7a1fb to your computer and use it in GitHub Desktop.
#define _GNU_SOURCE
#include <getopt.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#define NTHREADS 10 // upper limit on number of threads
static void
random_str(char* buf, size_t n)
{
const char* runes =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
struct timespec now = { 0 };
clock_gettime(CLOCK_MONOTONIC, &now);
long seed = now.tv_nsec + (1e9 * now.tv_sec);
srandom((unsigned int)seed);
for (size_t i = 0; i < n; i++) {
buf[i] = runes[random() % strlen(runes)];
}
}
typedef struct data data;
struct data
{
long ident;
size_t ret;
struct timespec time_limit;
char payload[1024];
};
static bool
deadline_exceeded(struct timespec* start, struct timespec* limit)
{
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
if ((now.tv_sec - start->tv_sec) > limit->tv_sec) {
return true;
}
return false;
}
void*
task(void* in)
{
const int pri = LOG_USER | LOG_INFO;
data* d;
d = (data*)in;
bool runtime_is_limited = d->time_limit.tv_sec != 0;
struct timespec start;
clock_gettime(CLOCK_MONOTONIC, &start);
size_t i = 0;
while (1) {
// Terminate if we ran past the deadline
if ((i > 0) && (i % 200 == 0)) {
d->ret = i;
if (runtime_is_limited && deadline_exceeded(&start, &d->time_limit)) {
goto done;
}
}
syslog(pri, "(%ld) %s [%zu]", d->ident, d->payload, i);
i++;
}
done:
pthread_exit((void*)d->ret);
}
int
main(int argc, char** argv)
{
int c;
int nthreads = 0;
int active_time_secs = 0;
// If we don't specify anything, just use the number of available CPUs
// as the thread count. It is hard to imagine more threads than CPUs
// will make things any better.
nthreads = (int)sysconf(_SC_NPROCESSORS_ONLN);
char* source = "test.source";
while (1) {
int option_index = 0;
static struct option long_options[] = {
{ "active-time-secs", required_argument, 0, 0 },
{ "threads", required_argument, 0, 1 },
{ "source", required_argument, 0, 2 },
{ 0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "012", long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 0:
// --active-time-secs argument
active_time_secs = atoi(optarg);
if (active_time_secs < 0) {
active_time_secs = 0;
}
printf("Setting active-time-secs = %d\n", active_time_secs);
break;
case 1:
// --threads argument
nthreads = atoi(optarg);
if (nthreads <= 0 || nthreads > NTHREADS) {
nthreads = NTHREADS;
}
printf("Setting nthreads = %d\n", nthreads);
break;
case 2:
// --source argument
source = optarg;
if (strlen(source) < 2) {
source = "test.source";
}
printf("Setting source = %s\n", source);
break;
case '?':
break;
default:
printf("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
long i;
int ret, stat = 0;
pthread_t tid[nthreads]; // Add one thread to account for main()
pthread_attr_t attr;
/* Init the thread attribute structure to defaults */
pthread_attr_init(&attr);
/* Create all threads as joinable */
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
openlog(source, LOG_NDELAY | LOG_PID, LOG_USER);
// Thread creation loop
for (i = 0; i < nthreads; i++) {
printf("main: creating thread #%ld ...\n", i);
data* dptr = (data*)malloc(sizeof(data));
dptr->ident = i;
dptr->time_limit.tv_sec = active_time_secs;
random_str(dptr->payload, 60);
ret = pthread_create(&tid[i], &attr, task, (void*)dptr);
if (ret)
printf("pthread_create() failed! [%d]\n", ret);
}
pthread_attr_destroy(&attr);
size_t tot_iters = 0;
// Wait and join all threads
for (i = 0; i < nthreads; i++) {
printf("main: waiting on thread #%ld\n", i);
size_t n;
ret = pthread_join(tid[i], (void*)&n);
tot_iters += n;
char msg[32] = { 0 };
if (ret) {
snprintf(msg, 32, "pthread_join() failed! [%ld]\n", i);
perror(msg);
} else {
printf("Thread #%ld successfully joined; it terminated with "
"status=%d\n",
i,
stat);
}
}
printf("Completed a total of %zu iterations\n", tot_iters);
pthread_exit(NULL);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment