JavaScript setInterval in C with pthreads

The goal is to output the string bar 4 times with a one second delay between each output:

bar
bar
bar
bar

In JavaScript:

let count = 0

function foo() {
  if (++count >= 4) clearInterval(interval)
  console.log('bar')
}

const interval = setInterval(foo, 1000) // every second

To replicate this in C we turn to pthread a library that handle the lifecycle of pthreads.

To compile the setInterval.c file with pthread:

gcc -Wall setInterval.c -lpthread -o setInterval.out

First attempt

#include <stdio.h>   // printf
#include <pthread.h> // pthread_t
#include <unistd.h>  // sleep

void *foo(void *vargp) {
  int count = 0;
  while(count++ < 4) {
    printf("bar\n");
    sleep(1); // one second
  }
  return NULL;
}

int main() {
  pthread_t thread_foo;
  pthread_create(&thread_foo, NULL, foo, NULL);
  pthread_join(thread_foo, NULL);
  return 0;
}

In the main function is where the main process kicks off. In that process we create a pthread to execute the foo function. Since we do not want the main process to exit right away we use the function pthread_join function to pause the calling thread, here the main process so it lets the pthread finish its work.

Second attempt

#include <stdio.h>   // printf
#include <pthread.h> // pthread_t
#include <unistd.h>  // sleep

void *foo(void *vargp) {
  int count = 0;
  while(1) {
    if (count++ >= 4) pthread_exit(NULL);
    printf("bar\n");
    sleep(1); // one second
  }
  return NULL;
}

int main() {
  pthread_t thread_foo;
  pthread_create(&thread_foo, NULL, foo, NULL);
  pthread_join(thread_foo, NULL);
  return 0;
}

Here we call the pthread_exit function before the foo function actually return. The pthread can exit itself.

Third attempt

#include <stdio.h>   // printf
#include <pthread.h> // pthread_t
#include <unistd.h>  // sleep

void *foo(void *vargp) {
  while(1) {
    printf("bar\n");
    sleep(1); // one second
  }
  return NULL;
}

int main() {
  pthread_t thread_foo;
  pthread_create(&thread_foo, NULL, foo, NULL);
  sleep(4);
  pthread_cancel(thread_foo);
  return 0;
}

In this example the main process is cancelling the pthread after waiting for 4 seconds with the pthread_cancel function.

Fourth attempt

#include <stdio.h>   // printf
#include <pthread.h> // pthread_t
#include <unistd.h>  // sleep

int RUNNING = 1;

void *foo(void *vargp) {
  while(RUNNING) {
    printf("bar\n");
    sleep(1); // one second
  }
  return NULL;
}

int main() {
  pthread_t thread_foo;
  pthread_create(&thread_foo, NULL, foo, NULL);
  sleep(4);
  RUNNING = 0;
  pthread_join(thread_foo, NULL);
  return 0;
}

We use the RUNNING global variable to communicate with the thread. On one hand that is considered bad practice. On the other hand it compiles and it has some upsides:

Note

For clarity purposes we removed all error handling in C:

  if(pthread_join(thread_foo, NULL) > 0) {
    printf("ERROR -> the pthread can not join");
    return 1;
  }
Mastodon