Skip to content

Instantly share code, notes, and snippets.

@Jukoo
Created February 18, 2025 12:23
Show Gist options
  • Select an option

  • Save Jukoo/a257d5861ab442d41229faa7da809bc1 to your computer and use it in GitHub Desktop.

Select an option

Save Jukoo/a257d5861ab442d41229faa7da809bc1 to your computer and use it in GitHub Desktop.
Basic use of posix thread (quick cheatsheet)
/* @author Umar Ba <jUmarB@protonmail.com>
* @Description :
* This code summarizes the essential use of the posix thread:
* -> Race Condition
* -> Data hosted by the thread itself
* -> Cleanup handler
* -> Thread attribute
*
* Happy Hacking /Reading ...
* please let me know if you want to see another concept.
*/
#define __USE_GNU
#include <stdlib.h>
#include <sys/uio.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <semaphore.h>
#include <error.h>
#include <errno.h>
#include <err.h>
#define nptr NULL
static int global_counter = 10 ;
static sem_t sem_index ;
struct __tmtx__ {
pthread_mutex_t _mtx ;
pthread_cond_t _cnd ;
} rchdl = {
PTHREAD_MUTEX_INITIALIZER ,
PTHREAD_COND_INITIALIZER
};
/*! This key can be used by each thread to access its own copy of the corresponding data object */
static pthread_key_t local_key ;
/* @fn tmsleep(int)
* @brief sleep function in millisec
* @param int - in millisec
**/
static void tmsleep(int millis) ;
/* @fn thread_echo(const char * , ...)
* @brief redirect to standard output and thread-specific data (e.g. file)
**/
static void thread_echo(const char * fmt , ...) ;
/* !-countdown thread routine */
void *count_down(void *args);
/*! - reset thread routine */
void *reset(void *args) ;
/*! - thread routine : update the global counter variable */
void *update_gcounter(void *args);
//!This function is automatically called by
//!the cleaning resource manager
extern __inline__ void release_local_key(void *args) {
if(!args) return ;
fclose((FILE *)args) ;
}
int main(void)
{
//! Disable buffering on stdout
setbuf(stdout , nptr) ;
//! Semaphore initialization
if(sem_init(&sem_index , 0 , 1))
{
perror("sem_init") ;
return EXIT_FAILURE ;
}
pthread_t th_cdown1 , th_cdown2 ,th_rst ,th_update_gc ;
pthread_attr_t th_attr ;
pthread_attr_init(&th_attr) ;
pthread_attr_setdetachstate(&th_attr , PTHREAD_CREATE_DETACHED) ;
//! Create a thread-specific data object.
//! but you can create as many thread-specific data objects as you like.
pthread_key_create(&local_key , release_local_key) ;
pthread_create(&th_cdown1 , nptr , count_down , nptr) ;
pthread_create(&th_cdown2 , nptr , count_down , nptr) ;
pthread_create(&th_update_gc , nptr , update_gcounter, nptr) ;
pthread_create(&th_rst , nptr , reset , nptr) ;
pthread_attr_destroy(&th_attr) ;
// cauz i use PTHREAD_CREATE_DETACHED
pthread_exit(0) ;
}
static void tmsleep(int millisec)
{
struct timespec ts = {
.tv_sec = (millisec / 1000),
.tv_nsec = (millisec % 1000) / 1000000UL
};
while((clock_nanosleep(CLOCK_REALTIME , 0 , &ts, nptr ) ==~0 && EINTR == errno)) ;
}
void * count_down(void *args)
{
//!Create thread specific filename -> thread{thread-idhex}
char thread_fn[0x14] = {0} ;
sprintf(thread_fn ,"thread%x", pthread_self()) ;
FILE * f = fopen(thread_fn , "w+") ;
if(!f)
goto __ending_thread ;
//!sets the value corresponding to this key pthread_key_t local_key
pthread_setspecific(local_key , f);
while(1)
{
thread_echo("-> %i \n" , global_counter--) ;
sem_wait(&sem_index) ;
if(global_counter <= 0 )
{
/* ! NOTE : You can try to use pthread_mutex_trylock
* But this is non-blocking function
* */
pthread_mutex_lock(&rchdl._mtx) ;
pthread_cond_signal(&rchdl._cnd) ;
pthread_mutex_unlock(&rchdl._mtx) ;
}
tmsleep(1000) ;
sem_post(&sem_index) ;
}
__ending_thread:
pthread_exit(0) ;
}
void *reset(void *args )
{
while(1)
{
pthread_mutex_lock(&rchdl._mtx) ;
pthread_cond_wait(&rchdl._cnd , &rchdl._mtx) ;
puts("reset") ;
sem_wait(&sem_index);
pthread_mutex_unlock(&rchdl._mtx) ;
}
pthread_exit(0) ;
}
void * update_gcounter(void *args)
{
//watch the status of global_counter
while(1)
{
if(global_counter == 0 )
{
pthread_mutex_lock(&rchdl._mtx) ;
puts("updating ... ") ;
while(50 > global_counter)
{
global_counter+= rand() %10 ;
if(50 < global_counter)
{
global_counter=50 ;
}
tmsleep(100) ;
fprintf(stdout , " %i % (filling the Gcounter )\r " , (global_counter*100)/50 ) ;
}
puts("") ;
global_counter=10 ;
pthread_mutex_unlock(&rchdl._mtx) ;
sem_post(&sem_index) ;
}
}
}
static void thread_echo(const char * fmt , ... )
{
va_list ap ;
va_start(ap , fmt) ;
char thread_buffer[200] = {0} ;
sprintf(thread_buffer , "thread 0x%x: ", pthread_self()) ;
struct iovec iv = {
thread_buffer ,
200
};
char fmtdata[160] = {0} ;
vsprintf(fmtdata , fmt , ap) ;
strcat(thread_buffer , fmtdata);
//! Obtain a thread-specific data object
FILE * tf = (FILE *) pthread_getspecific(local_key) ;
if (tf)
{
int fd = fileno(tf) ;
if(~0 != fd)
dprintf(fd, "%s", thread_buffer) ;
}else
warn("No able to write to this specific thread file : %i" , pthread_self() ) ;
writev(STDOUT_FILENO, &iv , 1 ) ;
va_end(ap);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment