From 6c92c970e41026a9f0ffcbad344f1fecb9f1709f Mon Sep 17 00:00:00 2001 From: AfonsoCMSousa Date: Wed, 12 Mar 2025 03:45:26 +0000 Subject: [PATCH] First Commit and release of a stable build. --- CMakeLists.txt | 23 ++ bin/example | Bin 0 -> 34696 bytes build.sh | 6 + example | Bin 0 -> 56856 bytes guide.md | 525 ++++++++++++++++++++++++++++++++++ include/threadlib/threadlib.c | 190 ++++++++++++ include/threadlib/threadlib.h | 101 +++++++ src/main.c | 41 +++ 8 files changed, 886 insertions(+) create mode 100644 CMakeLists.txt create mode 100755 bin/example create mode 100755 build.sh create mode 100755 example create mode 100644 guide.md create mode 100644 include/threadlib/threadlib.c create mode 100644 include/threadlib/threadlib.h create mode 100644 src/main.c diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..16ab79b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.21) + +# Project Name and App Name +set(APP_NAME "example") +set(APP_PROJECT "PROJECT THREADMASTERR") + +# Folder Names and Locations +set(SOURCE "./src") +set(BINARIES "./bin") + +# Set the project name and version +project(${APP_PROJECT} VERSION 1.0) + +# Specify the C standard +set(CMAKE_C_STANDARD 17) + +# Include header files from the include directory +include_directories(${CMAKE_SOURCE_DIR}/include) + +add_executable(${APP_NAME} ${SOURCE}/main.c ${CMAKE_SOURCE_DIR}/include/threadlib/threadlib.c) + +# Display a message when compiling +message(STATUS "Compiling ${APP_NAME}...") \ No newline at end of file diff --git a/bin/example b/bin/example new file mode 100755 index 0000000000000000000000000000000000000000..0d419c7c7d23494a7a37c96af09b489340becf6c GIT binary patch literal 34696 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

F2q1|&0g4^4czj04mGslaPK!d8lm z*?fmT3%Msr&fVd|4UeGMdIsNvUid~ zsjj_0-?jHc?iJiwOLXniD7IG1@aS{X@Y)}tAiJu6+Ouh*Y7n;(akv@-(fXkDFGtlh z3TbG`#qrqmJv5Wl=O*`fY#rKrB7or-7}{U|NpUO5r$sZDEH<_*Y^>%7?4wJgX=U?Y4I$@n|8<{{K z?vl#5ot#Xcf^1DZ0<`C%~J@GGcWTVA4d zqv5i=yYJ4s3rcru&!oEHhAWWqF7Sqzv3T5rTIa@THQn;v!@;reHcaETXPwP~RQwl^ z+A_R?agR-1Eo!W%@g-liae6D@6BQqB$CrLFh8{uwI>v_^J`VxwJJ3cehbwL;aeVfA z1qBHGWq80^dxTK`> zHe_XzcSSWx`L$1@px8L0T}g4FL*(#@z290(NGVLXMD{9!2w` zF4OR%R)k+Qun)t=IZpBUzT$K;SZbWUoFAtzL+&}4C^18xLa{|}3(z=)y|v>g$lv5= zF_^^kaYbH)Oq3k1Qzau<(o>BAv`G>;)nD(a8pNg+O;m0Na4qNKQ;5HooR?~+e2}&t zqPI04f!s=xbIc2#k271*&NHMhx}OZMJ%WPyJ03a#BV{Lw+}(B;J}ey`{iH`&%}}2H znEdS2un&^57cY8V_G*Hx&p;bJd=*_ErE9F)SV%D(o+i})c%5_ct2$dg53mxbv%a9j zzt@86D6R{h7kraS)3P)_HkR_TGdU?DC%9<$bsJ2EVs)o8P-_drQkTEmwQn1J|^9+Z)@i#eL(C zJ{Ggz;=f^8KAO_WR6Oc!4JLxo@*We zZz}HX##@ic-ZyBQNGr0>HkCp1jfPv)5B@|Vp18t$RWKYeyC_n6Ju@7Pg#X6$M$>qg zwC0Zp+To?hewT^&A>+IMB*uv!IsE47FLD=*MB<@f3XL(N@x*S~FDW%<`|twOGFw;N zKW*ty2=4`6;oXL5v3uF(MNxx7XfT??ZHUTow+uJ#@zo^FFMU|8UftH-*uK4Op;5y2 z<@#{V<}Ln(H`yWtXUIqslH7;iPK6nt$8Uu^7FC9SJ8>?V^vCR3X<8 zq0Ad$Yz}6G*IhIRXRPH@Vcsj5fXnl)x;SjCPkWakHm{C5eGo(wnoOAlf zKp5&WS9i_oOeJG{!jk1`@KtB%qX5a%UW#&j+LJkLg$P%1Ud{O_oZ|sMj_S;tIX{i_ zb)3`32&zAw^D|^FGAh$&&46Y=GoTsJ3}^;41DXNNfM!55pc&8%Xa+O`ngPv#WGy|Fe&46Y=GoTsJ3}^;41DXNNfM!55pc&8%Xa+O` zngPv#W?g&#`5#p9vYoS7|C{pvyZ3Qvapq-x^*ajqjRqFEbcy=D1@y02qW%=O z-~OG64)$;N|3dNG{qMVy6zT+ijzS(CoZJ1snEoj1zn}FooZJ1sm_Ge~@8sXddL5km z7HPj7zxTbQP#nKKeirjTwSfPtmgqmj{?~Kd9h}?aZ&ClOeYtk%0~kz=gZFX-O_b^4#^<#?b zGgjjR`ixb7L!YtgKj;rCebpb(mzc`*p&8H&Xa+O`ngPv#WGy|Fe&46Y=GoTsJ3}^;41DXNNfM!55pc&8%Xa+O`ngPv#WGy|Fe&46a$FOLB)LhePHM56bIJxKOZVP7CW1F4QNT?^ky z`4?^hNpHS91HcEBd&-b5MQTBcAbkbtNu<}1F7^n|^+*RiqHGrFv@%h4G1BEo0i<@M zE~FIFT}a1)tfMbT}BA!6zXl1H}+u!B`RHV(RuXu|kZr;WTp{PLr(y z!$7$;3~?H{LVl(w3#vX-xJrg6&JtzO;4VY8DJfQQcvguW!vv5G694T{O?jTgn;;n# z17$bI6FU*$* z5sZqvJxquAoMc15{^*Kad8XX!t**;>y!bb^YNTSUeDtKL6(|!cF}+U4M4r45T?GEl zWIV(8U5rJ&s&8QIWxSPexe#8w-%k458Pogjgl}X_@4FK=ZF&4Y1>vYI&p2(%Gv33P z-d`vAe#Z3vI^is1dS9LJos8-Ibi$uwJjM8+Esyunss5{seT=_u>ofiqV|qWG9 z@23;~K4W@6o$yZxufjz};c3P`#&e7_jMsrXlFu=I7h`(wpX@a&{Nyc@IpJD7{e4KGB<8xQ4csm$xV%*1g zE8`4flko`SJ&Z>g-@$l{@s}9q7=N4bB;%g|pS4DaDaOxJ{hPq|e%0Pt#`Jp-)E|_( z=)}jV_`#bl8z66V;Q(;=3Xgd6OOrh$MyfS9&Ad}xUy1AU92l44Jfu;&z(HAytDf{n z&Q*1vMm_1|{dD0gyeP_MYzfkFa7VVSzjBR}{ z*}y@V{M+j-VbZtPTUvi*`xnu-(>RY^^34C zqhhD^i*SZ9tzU$5jA{Ln`nM=~ny(kQ<||?6d?oChuY{fRm9RZuX?%J`{viIk=)}iY zUE|Gi;TL)QP5-`d{I#xE@ixH@@o!@?eI8NPf#3ie&p#oJilsR7Uz)Y7Y_hQ`AL73uq)|0;Xa#cs4l_-82lPJYMMHe_IBYkJR^w0Yt+Aop5yY<@$1q;-;H%hB57L!Ej_BT?0K|;#(5yGvEX+J`^gE8$#2=_6j{RrU}p9$`%T5yGR4?_fN}nD!%7pJPn>5yF#< zV`!Qe$v!|+0sg!Tm$~pk7k-}XyY@4L7uwH|y(;X7I`*snqV=%~1Iu3jXuT$Eug6V{ z?fb)rB(BC;=~H{io?v^_9>QM6wErM`_WpwQGt%F=N}t+G@;;WQ_7U!7OzSVn+v_W> zXN2wb>L_D-{iF3(`s4MN?jMBv_ldaN)mq z;jg>!gbV-DgCekYT{!8&dtA8Rh3|CXgD(8A z3;%};<8fF)JhLu5=fc##&mjE<=~*NTX&UK&kp36x7}9T%{tsye>3O8zA-#a~BGT`X zUP5{qX%^`fq*sxSBb`8cBle$z{2${3YQjrTy_^qv0PROT1&@Us<<93PswZ`Y4RSnLa!IR)Z??3v znR&0Wv_O!bD1iq3;Pfx`!Kv)JnrOT$O^<}})L9gibQP5>BvXT@y27Ay%?8dd;d~?K zc%HpvGQD!#SRROD~%^-+<@W$}RlzP*l&~*;{cLMOdN~@s=n>^d(C3&*s_J z0u#JYm8W}QAy4+gLPb<@*-}H757kRXUeq3Y+UHljnuWEC+AXO^UzG?IJy)U>{aB(j z|5pu1-_@XxOUP1>mnzQpYG*ixr}BmU?spjh_5 zx)<>u;P59r^>;b53xBqvJ6QgHRy5pew +#include +#include +#include "threadlib/threadlib.h" + +#define MAX_THREAD 2 + +typedef struct custom_params_t +{ + int a; +} custom_params_t; + +void *thread_worker(void *params) +{ + worker_param_t *param = (worker_param_t *)params; + // custom_params_t *custom = (custom_params_t *)param->custom_params; + + if (param->thread_id == 3) + { + param->status = IDLE; + return NULL; + } + + printf("Thread %d - WE ARE RUNNING THIS TASK\n", param->thread_id); + + param->status = IDLE; + return NULL; +} + +int main(void) +{ + custom_params_t *custom_params = (custom_params_t *)malloc(sizeof(custom_params_t)); + custom_params->a = 0; + thread_master_init(MAX_THREAD, thread_worker, NULL); + + thread_master_free(); + printf("Custom Params: %d\n", custom_params->a); + return 0; +} +``` + +### include/threadlib/threadlib.h + +This header file declares the functions and structures used in the thread library. It provides the necessary declarations for initializing and managing threads, as well as handling mutexes. + +```c +#ifndef THREADLIB_H +#define THREADLIB_H + +#include +#include +#include + +#ifdef _WIN32 +#include +#define sleep_ms(x) Sleep(x) +#else +#define sleep_ms(x) usleep(x * 1000) +#include +#endif + +typedef struct worker_param_t +{ + int thread_id; + enum status + { + IDLE, + BUSY + } status; + pthread_mutex_t *mutex; + void *custom_params; // User-defined parameters +} worker_param_t; + +typedef struct thread +{ + pthread_t thread; + worker_param_t worker_param; +} thread; + +typedef struct thread_master_param_t +{ + int max_threads; + pthread_mutex_t mutex; + void *(*__thread_worker__)(void *); // task to be done by the worker + void *custom_params; // User-defined parameters +} thread_master_param_t; + +/** + * @brief Initializes the thread master with a specified number of threads and a worker function. + * + * @param max_threads The maximum possible number of threads to be used. + * @param thread_worker The function pointer to the worker function that each thread will execute. + * @param custom_params Custom parameters to be passed to the worker function. + */ +void thread_master_init(int max_threads, void *(*__thread_worker__)(void *), void *custom_params); + +/** + * @brief Initializes a mutex. + * + * @param mutex Pointer to the mutex to be initialized. + */ +void thread_mutex_init(pthread_mutex_t *mutex); + +/** + * @brief Destroys a mutex. + * + * @param mutex Pointer to the mutex to be destroyed. + */ +void thread_mutex_destroy(pthread_mutex_t *mutex); + +/** + * @brief Frees resources allocated by the thread master. + */ +void thread_master_free(); + +/** + * @brief Retrieves the status of the thread master. + */ +void thread_master_get_status(); + +/** + * @brief Assigns a new job to the thread workers. + * + * @param thread_worker The function pointer to the worker function that each thread will execute. + * @param custom_params Custom parameters to be passed to the worker function. + */ +void thread_master_assign_new_job(void *(*__thread_worker__)(void *), void *custom_params); + +/** + * Example of usage: + * + * void *worker_function(void *param) { + * worker_param_t *worker_param = (worker_param_t *)param; + * printf("Thread %d is working\n", worker_param->thread_id); + * sleep_ms(1000); // Simulate work + * return NULL; + * } + * + * int main() { + * thread_master_init(4, worker_function, NULL); + * // Do some work + * thread_master_free(); + * return 0; + * } + */ + +#endif // !THREADLIB_H +``` + +### include/threadlib/threadlib.c + +This file contains the implementation of the thread library functions. It includes the logic for initializing the thread master, creating and managing threads, and handling mutexes. + +```c +#include "threadlib/threadlib.h" + +int __max_threads; +unsigned char isThreadMasterRunning = 0; +thread *listT = NULL; +thread_master_param_t *param = NULL; +pthread_t thread_master; + +static pthread_mutex_t mutex; + +void __thread_mutex_init__(pthread_mutex_t *mutex) +{ + if (pthread_mutex_init(mutex, NULL) != 0) + { + fprintf(stderr, "Error: Failed to initialize mutex.\n"); + exit(EXIT_FAILURE); + } +} + +void thread_mutex_init(pthread_mutex_t *mutex) +{ + __thread_mutex_init__(mutex); +} + +void __thread_mutex_destroy__(pthread_mutex_t *mutex) +{ + if (pthread_mutex_destroy(mutex) != 0) + { + fprintf(stderr, "Error: Failed to destroy mutex.\n"); + exit(EXIT_FAILURE); + } +} + +void thread_mutex_destroy(pthread_mutex_t *mutex) +{ + __thread_mutex_destroy__(mutex); +} + +void *__thread_master_init__(void *params) +{ + thread_master_param_t *param = (thread_master_param_t *)params; + + listT = (thread *)malloc(param->max_threads * sizeof(thread)); + if (listT == NULL) + { + fprintf(stderr, "Tread Master - Error: Failed to allocate memory for thread pool.\n"); + return NULL; + } + + thread_mutex_init(&mutex); + + __max_threads = param->max_threads; + + for (int i = 0; i < param->max_threads; i++) + { + listT[i].worker_param.thread_id = i + 1; + listT[i].worker_param.mutex = &mutex; + listT[i].worker_param.status = IDLE; + listT[i].worker_param.custom_params = param->custom_params; + } + + printf("Thread Master - Success: Ready.\n"); + + thread_master_assign_new_job(param->__thread_worker__, param->custom_params); + + return NULL; +} + +void thread_master_init(int max_threads, void *(*__thread_worker__)(void *), void *custom_params) +{ + param = (thread_master_param_t *)malloc(sizeof(thread_master_param_t)); + + param->max_threads = max_threads; + param->__thread_worker__ = __thread_worker__; + param->mutex = mutex; + param->custom_params = custom_params; + + static pthread_mutex_t mutex; + __thread_mutex_init__(&mutex); + + param->mutex = mutex; + + if (pthread_create(&thread_master, NULL, __thread_master_init__, (void *)param) != 0) + { + fprintf(stderr, "Error: Failed to create thread master.\n"); + exit(EXIT_FAILURE); + } + isThreadMasterRunning = 1; + + pthread_detach(thread_master); + printf("Thread Master - Created\n"); +} + +void thread_master_assign_new_job(void *(*__thread_worker__)(void *), void *custom_params) +{ + for (int i = 0; i < __max_threads; i++) + { + if (listT[i].worker_param.status == IDLE) + { + listT[i].worker_param.status = BUSY; + listT[i].worker_param.custom_params = custom_params; + pthread_create(&(listT[i].thread), NULL, __thread_worker__, &(listT[i].worker_param)); + break; + } + + if (i == __max_threads - 1) + { + sleep_ms(10); + i = 0; + } + } +} + +void thread_master_get_status() +{ + printf("\n\nSTATUS\n"); + do + { +#ifdef DEBUG + printf("Thread Master - Waiting for status\n"); + printf("Thread Master - Max Threads: %d\n", __max_threads); + printf("Param: %d\n", param->max_threads); +#endif // DEBUG + sleep(1); + } while (__max_threads == 0); + + pthread_mutex_lock(¶m->mutex); + for (int i = 0; i < __max_threads; i++) + { + switch (listT[i].worker_param.status) + { + case IDLE: + printf("Thread %d - IDLE\n", listT[i].worker_param.thread_id); + break; + case BUSY: + printf("Thread %d - BUSY\n", listT[i].worker_param.thread_id); + isThreadMasterRunning = 1; + break; + default: + printf("Thread %d - UNKNOWN\n", listT[i].worker_param.thread_id); + break; + } + } + pthread_mutex_unlock(¶m->mutex); + printf("END STATUS\n"); +} + +void thread_master_free() +{ + while (isThreadMasterRunning) + { +#ifdef DEBUG + printf("Thread Master - Waiting for workers to finish\n"); +#endif // DEBUG + + for (int i = 0; i < __max_threads; i++) + { + if (listT[i].worker_param.status == BUSY) + { + break; + } + if (i == __max_threads - 1) + { + isThreadMasterRunning = 0; + } + } + sleep_ms(100); + } + + __thread_mutex_destroy__(¶m->mutex); + free(param); + free(listT); + printf("Thread Master - Free and Stopped\n"); +} +``` + +### Usage Example + +This example demonstrates how to use the thread library to create and manage threads. + +```c +void *worker_function(void *param) { + worker_param_t *worker_param = (worker_param_t *)param; + printf("Thread %d is working\n", worker_param->thread_id); + sleep_ms(1000); // Simulate work + + // Be sure to include this, otherwise the master won't know which threads are available + param->status = IDLE; + return NULL; +} + +int main() { + thread_master_init(4, worker_function, NULL); + // Do some work + thread_master_free(); + return 0; +} +``` + +Of course, you can create your custom parameters and use them as you please. + +```c +/* Don't forget the includes */ + +typedef struct custom_params_t +{ + int my_custom_variable; +} custom_params_t; + +void *worker_function(void *param) { + worker_param_t *worker_param = (worker_param_t *)param; + custom_params_t *my_custom_params = (worker_param_t *)param->custom_params; + + printf("Thread %d is working\n", worker_param->thread_id); + sleep_ms(1000); // Simulate work + + printf("%d\n", my_custom_params->my_custom_variable); // stdout: 42 + + // Be sure to include this, otherwise the master won't know which threads are available + param->status = IDLE; + return NULL; +} + +int main() { + custom_params_t my_params = (custom_params_t *)malloc(sizeof(custom_params_t)); // It's recommended to use the heap + my_params->my_custom_variable = 42; + + thread_master_init(4, worker_function, my_params); + + // Do some work + + printf("%d\n", my_params->my_custom_variable); + // Of course, the value may not have changed by here + // it depends on how fast the thread work is + + thread_master_free(); + free(my_params); // Dont forget to free your custom parameters + return 0; +} +``` + +You can assign new tasks to the other threads if one is busy. + +```c +void *worker_function(void *param) { + worker_param_t *worker_param = (worker_param_t *)param; + + printf("Thread %d is working\n", worker_param->thread_id); + sleep_ms(1000); // Simulate work + + // Be sure to include this, otherwise the master won't know which threads are available + param->status = IDLE; + return NULL; +} + +void *new_task(void *param) { + worker_param_t *worker_param = (worker_param_t *)param; + + printf("Thread %d is working on another task\n", worker_param->thread_id); + sleep_ms(2000); // Simulate work + + param->status = IDLE; + return NULL; +} + +int main() { + custom_params_t my_params = (custom_params_t *)malloc(sizeof(custom_params_t)); // It's recommended to use the heap + my_params->my_custom_variable = 42; + + thread_master_init(4, worker_function, my_params); + + // Do some work + + thread_master_assign_new_job(new_task, NULL); // Instead of NULL you can include other custom parameters + + printf("%d\n", my_params->my_custom_variable); + // Of course, the value may not have changed by here + // it depends on how fast the thread work is + + thread_master_free(); + free(my_params); // Dont forget to free your custom parameters + return 0; +} +``` + +### A big thanks to: +- Professor **Marco Ferreira** - +- Professor **PatrĂ­cio Domingues** - diff --git a/include/threadlib/threadlib.c b/include/threadlib/threadlib.c new file mode 100644 index 0000000..c60d8e2 --- /dev/null +++ b/include/threadlib/threadlib.c @@ -0,0 +1,190 @@ +#include "threadlib/threadlib.h" + +int __max_threads; +unsigned char isThreadMasterRunning = 0; +thread *listT = NULL; +thread_master_param_t *param = NULL; +pthread_t thread_master; + +static pthread_mutex_t mutex; + +void __thread_mutex_init__(pthread_mutex_t *mutex) +{ + if (pthread_mutex_init(mutex, NULL) != 0) + { + fprintf(stderr, "Error: Failed to initialize mutex.\n"); + exit(EXIT_FAILURE); + } +} + +void thread_mutex_init(pthread_mutex_t *mutex) +{ + __thread_mutex_init__(mutex); +} + +void __thread_mutex_destroy__(pthread_mutex_t *mutex) +{ + if (pthread_mutex_destroy(mutex) != 0) + { + fprintf(stderr, "Error: Failed to destroy mutex.\n"); + exit(EXIT_FAILURE); + } +} + +void thread_mutex_destroy(pthread_mutex_t *mutex) +{ + __thread_mutex_destroy__(mutex); +} + +void *__thread_master_init__(void *params) +{ + thread_master_param_t *param = (thread_master_param_t *)params; + + listT = (thread *)malloc(param->max_threads * sizeof(thread)); + if (listT == NULL) + { + fprintf(stderr, "Tread Master - Error: Failed to allocate memory for thread pool.\n"); + return NULL; + } + + thread_mutex_init(&mutex); + + __max_threads = param->max_threads; + + for (int i = 0; i < param->max_threads; i++) + { + listT[i].worker_param.thread_id = i + 1; + listT[i].worker_param.mutex = &mutex; + listT[i].worker_param.status = IDLE; + listT[i].worker_param.custom_params = param->custom_params; + } + + printf("Thread Master - Success: Ready.\n"); + + thread_master_assign_new_job(param->__thread_worker__, param->custom_params); + + /* for (int i = 0; i < param->max_threads; i++) + { + // 3 - Create the threads + if (pthread_create(&(listT[i].thread), NULL, param->__thread_worker__, &(listT[i].worker_param)) != 0) + { + fprintf(stderr, "Error: Failed to create thread %d.\n", i + 1); + exit(EXIT_FAILURE); + } + listT[i].worker_param.status = BUSY; + } + + for (int i = 0; i < param->max_threads; i++) + { + pthread_join(listT[i].thread, NULL); + }*/ + return NULL; +} + +void thread_master_init(int max_threads, void *(*__thread_worker__)(void *), void *custom_params) +{ + param = (thread_master_param_t *)malloc(sizeof(thread_master_param_t)); + + param->max_threads = max_threads; + param->__thread_worker__ = __thread_worker__; + param->mutex = mutex; + param->custom_params = custom_params; + + static pthread_mutex_t mutex; + __thread_mutex_init__(&mutex); + + param->mutex = mutex; + + if (pthread_create(&thread_master, NULL, __thread_master_init__, (void *)param) != 0) + { + fprintf(stderr, "Error: Failed to create thread master.\n"); + exit(EXIT_FAILURE); + } + isThreadMasterRunning = 1; + + pthread_detach(thread_master); + printf("Thread Master - Created\n"); +} + +void thread_master_assign_new_job(void *(*__thread_worker__)(void *), void *custom_params) +{ + for (int i = 0; i < __max_threads; i++) + { + if (listT[i].worker_param.status == IDLE) + { + listT[i].worker_param.status = BUSY; + listT[i].worker_param.custom_params = custom_params; + pthread_create(&(listT[i].thread), NULL, __thread_worker__, &(listT[i].worker_param)); + break; + } + + if (i == __max_threads - 1) + { + sleep_ms(10); + i = 0; + } + } +} + +void thread_master_get_status() +{ + printf("\n\nSTATUS\n"); + do + { +#ifdef DEBUG + printf("Thread Master - Waiting for status\n"); + printf("Thread Master - Max Threads: %d\n", __max_threads); + printf("Param: %d\n", param->max_threads); +#endif // DEBUG + sleep(1); + } while (__max_threads == 0); + + pthread_mutex_lock(¶m->mutex); + for (int i = 0; i < __max_threads; i++) + { + switch (listT[i].worker_param.status) + { + case IDLE: + printf("Thread %d - IDLE\n", listT[i].worker_param.thread_id); + break; + case BUSY: + printf("Thread %d - BUSY\n", listT[i].worker_param.thread_id); + isThreadMasterRunning = 1; + break; + default: + printf("Thread %d - UNKNOWN\n", listT[i].worker_param.thread_id); + break; + } + } + pthread_mutex_unlock(¶m->mutex); + printf("END STATUS\n"); +} + +void thread_master_free() +{ + while (isThreadMasterRunning) + { +#ifdef DEBUG + printf("Thread Master - Waiting for workers to finish\n"); +#endif // DEBUG + + for (int i = 0; i < __max_threads; i++) + { + // check if all threads are IDLE + if (listT[i].worker_param.status == BUSY) + { + break; + } + if (i == __max_threads - 1) + { + isThreadMasterRunning = 0; + } + } + sleep_ms(100); + } + + __thread_mutex_destroy__(¶m->mutex); + free(param); + free(listT); + printf("Thread Master - Free and Stopped\n"); +} \ No newline at end of file diff --git a/include/threadlib/threadlib.h b/include/threadlib/threadlib.h new file mode 100644 index 0000000..ec27c51 --- /dev/null +++ b/include/threadlib/threadlib.h @@ -0,0 +1,101 @@ +#ifndef THREADLIB_H +#define THREADLIB_H + +#include +#include +#include + +#ifdef _WIN32 +#include +#define sleep_ms(x) Sleep(x) +#else +#define sleep_ms(x) usleep(x * 1000) +#include +#endif + +typedef struct worker_param_t +{ + int thread_id; + enum status + { + IDLE, + BUSY + } status; + pthread_mutex_t *mutex; + void *custom_params; // User-defined parameters +} worker_param_t; + +typedef struct thread +{ + pthread_t thread; + worker_param_t worker_param; +} thread; + +typedef struct thread_master_param_t +{ + int max_threads; + pthread_mutex_t mutex; + void *(*__thread_worker__)(void *); // task to be done by the worker + void *custom_params; // User-defined parameters +} thread_master_param_t; + +/** + * @brief Initializes the thread master with a specified number of threads and a worker function. + * + * @param max_threads The maximum possible number of threads to be used. + * @param thread_worker The function pointer to the worker function that each thread will execute. + * @param custom_params Custom parameters to be passed to the worker function. + */ +void thread_master_init(int max_threads, void *(*__thread_worker__)(void *), void *custom_params); + +/** + * @brief Initializes a mutex. + * + * @param mutex Pointer to the mutex to be initialized. + */ +void thread_mutex_init(pthread_mutex_t *mutex); + +/** + * @brief Destroys a mutex. + * + * @param mutex Pointer to the mutex to be destroyed. + */ +void thread_mutex_destroy(pthread_mutex_t *mutex); + +/** + * @brief Frees resources allocated by the thread master. + */ +void thread_master_free(); + +/** + * @brief Retrieves the status of the thread master. + */ +void thread_master_get_status(); + +/** + * @brief Assigns a new job to the thread workers. + * + * @param thread_worker The function pointer to the worker function that each thread will execute. + * @param custom_params Custom parameters to be passed to the worker function. + */ +void thread_master_assign_new_job(void *(*__thread_worker__)(void *), void *custom_params); + +/** + * Example of usage: + * + * void *worker_function(void *param) { + * worker_param_t *worker_param = (worker_param_t *)param; + * printf("Thread %d is working\n", worker_param->thread_id); + * sleep_ms(1000); // Simulate work + * return NULL; + * } + * + * int main() { + * thread_master_init(4, worker_function, NULL); + * // Do some work + * thread_master_free(); + * return 0; + * } + */ + +#endif // !THREADLIB_H \ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..5b8ed9b --- /dev/null +++ b/src/main.c @@ -0,0 +1,41 @@ +#include +#include + +#include "threadlib/threadlib.h" + +#define MAX_THREAD 2 + +typedef struct custom_params_t +{ + int a; +} custom_params_t; + +void *thread_worker(void *params) +{ + worker_param_t *param = (worker_param_t *)params; + custom_params_t *custom = (custom_params_t *)param->custom_params; + + if (param->thread_id == 3) + { + param->status = IDLE; + return NULL; + } + + custom->a += 10; + + printf("Thread %d - WE ARE RUNNING THIS TASK\n", param->thread_id); + + param->status = IDLE; + return NULL; +} + +int main(void) +{ + custom_params_t *custom_params = (custom_params_t *)malloc(sizeof(custom_params_t)); + custom_params->a = 0; + thread_master_init(MAX_THREAD, thread_worker, NULL); + + thread_master_free(); + printf("Custom Params: %d\n", custom_params->a); + return 0; +} \ No newline at end of file