It is a shame that you do not have more views. This video and the previous one on thread pools are probably the two most simplistic and best implementations of thread pools in C using pthread anywhere on the internet. Thank you so much for sharing this.
believe that. I am a professional with lots of hardware experience. You are spot on. Dont worry about the no views it will come but you're right. This guy is spot on.
Hello! I'm from Brazil, here we have severals good C programers, but, them generaly do not share knolegment, so that's why I'm watching your videos, congratulations for the good classes and don't stop, you are helping loads of people from all over the world. Thankyou very mutch!
I like this kind of explanation which I compare to peeling bananas and slowly feeding it to babies. Thank you for sharing knowledge. As an experienced C programmer, watching all the thread videos in these channel gave me good refreshment of concepts in detail.
Hi! Your video series explain most concepts about multithreading, but you've missed one concept which is not even found on any websites. It is the use of multithreading dynamically. A program that creates multiple number of threads depending on the input of the user. Could you please make a video of that as well. Suppose a program needs to be created that prints numbers between 0 to 1000 but the threads are dynamic depending on the user input. So, it needs to be split into n numbers as users want it. How is it done? Thank you in advance.
Great vid! I've managed to mostly port this over to Windows using its API, but I have a question not touched on here. What's the best way to keep track of when your threads are all complete? Say we have a huge physics simulation we're running, so we want to throw the work at a bunch of threads, but we don't want to continue on the main thread until all the work is complete. Would we simply use the same mutex and add a counter that we increment and decrement on job start/completion? then we simply sleep the main thread until this counter is 0?
Yes, or you could use a timeout when the job count goes to 0 and, once that happens, simply stop the process. You might need a separate thread for that
First of all, thank you very much for your videos, they are excellent! Would be really cool if you made a video talking about the problem of readers/writers, introducing the use of pthread_rwlock_t
Say you have 2 or more threads running the same function at the same time. Is this a concern for race conditions? I’m trying to multithread a function that does some computation from global inputs, and sets it equal to a global output. The inputs and outputs are global arrays, but I’m sending it different index numbers. Would race conditions occur in this set up? Thanks for the videos, they’re great.
sir I would like to ask you what if lets say we created a number of threads and we would want to execute each function at certain time periods so we would have them waiting for certain signals would we still get benefit from using threadpools and the producer consumer logic??
The thread pools are specifically made to abstract when and how the jobs get executed... So, in this situation it would be wise to not use thread pools. Although, there might be some situations where this is useful
I tried to trace how the threads work by adding print statements and I noticed that in the end, the loop that calls pthread_join() on each thread in th[] does not completely execute. After entering the loop and reading the first join the program is stuck. What is causing this?
That's intended. pthread_join basically returns only after the thread you joined finished its execution (so effectively puts the main thread to sleep until then). This is so that you can wait for your threads to finish execution before stopping the whole process. Otherwise, you would end up calling return; on the main function in the main thread, stopping the process, which would also stop all the threads regardless if they are running or not
{ while (1) { int time = 0; Task task; int found = 0; // pthread_mutex_lock (&mutexQueue); // while (taskCount == 0) { // pthread_cond_wait (&condQueue, &mutexQueue); // } if (taskCount > 0) { found = 1; task = taskQueue[0]; for (int i = 0; i < taskCount - 1; i++) { taskQueue[i] = taskQueue[i + 1]; } taskCount--; } // pthread_mutex_unlock (&mutexQueue); if (found == 1) { executeTask (&task); } if (time == 0) { return NULL; } } } I did not use pthread_mutex_lock and it worked and with return NULL the thread join worked ;)
Hi! I have been running tests using thread pools in order to provide accurate comparable timings when it comes to using high performance computing on an algorithm I've been playing around with (my masters thesis!) This code never reaches the return at the end of the main() function. The Pthread_Join() function appears to be the problem as the threads in the threadpool never return or call pthread_exit() in order to leave the while(1) loop, so it simply hangs on the join function. I understand that there needs to be a way to keep those threads alive long enough that they can finish their work without the main thread destroying them, but this solution doesn't allow the program to end, and the tests that I need to run need to allow for multiple different sized thread pools, so I need to be able to destroy and recreate pools multiple times in one run of the executable. I've looked into my own solutions to this problem, but to no avail. Is there a graceful way to get the threads off the cond_wait and join without having to call pthread_cancel()?
A simple solution would be to add a special task to the queue that makes the threads exit. You can send it from the main thread when you finished processing what you wanted. Another solution would be to remove the while(1) in the loops and just have them execute a predefined number of tasks
First, great videos man, you explain so well and carefully this topic. Thank You so much. I got a question, I know that in the video you use an example of random numbers that add to each other, but in a program were I have to print the output (result) in an ordered way, how can I do that without serializing the program?. It doesn't matter the order of the execution of the threads, I only want the output to be in an ordered way. Thank you!
Uhmm, I suppose if you want just your output to be ordered in some way you could simply sort it (in an array) based on some index after everything is done (or on every insertion). Either that or you give each thread a unique index where they should store the results
Hello! This playlist is really great thank you! I have a question how can I actually avoid using global variables, like int taskCount and Task taskQueue?
Thank you for the video. Isn't there any better way to update taskQueue array not by shifting the tasks every time? It takes O(N) time for every visit.
@ It's not a circular queue, it always takes 0 index value after shifting. for (i = 0; i < taskCount - 1; i++) { taskQueue[i] = taskQueue[i + 1]; } It may not be an issue if taskCount is small otherwise it costs some time.
If you implement the queue on a linked list and not on an array, the complexity when updating should be O(1). Maybe you also need to store both head and tail of the list.
@@CodeVault Thank you , linked list can be the right solution as you said. I was thinking circular queue with an array but it may be also concerned for overflow situation.
It is a shame that you do not have more views. This video and the previous one on thread pools are probably the two most simplistic and best implementations of thread pools in C using pthread anywhere on the internet. Thank you so much for sharing this.
believe that. I am a professional with lots of hardware experience. You are spot on. Dont worry about the no views it will come but you're right. This guy is spot on.
learnt more in these 2 videos than 1 year of learning C, amazing
Lol, for real
Great people do tougher things in simple way & you are one of them, great job done :)
I just finished watching playlists on processes and threads. Thank you so much for the content!
Hi thanks for greate explanation, I just solved the homework like tihs:
#include
#include
#include
#include
#include
#include
#define THREAD_NUM 4
#define TASK_COUNT 100
typedef struct Task {
void (*taskFunction)(int, int, int*);
int arg1, arg2;
int* result;
} Task;
Task taskQueue[256];
int taskCount = 0;
pthread_mutex_t mutexQueue;
pthread_cond_t condQueue;
void sum(int a, int b, int* result) {
usleep(50000);
*result = a + b;
}
void product(int a, int b, int* result) {
usleep(50000);
*result = a * b;
}
void executeTask(Task* task) {
task->taskFunction(task->arg1, task->arg2, task->result);
printf("Result of task (%d, %d) is %d
", task->arg1, task->arg2, *(task->result));
}
void submitTask(Task task) {
pthread_mutex_lock(&mutexQueue);
taskQueue[taskCount] = task;
taskCount++;
pthread_mutex_unlock(&mutexQueue);
pthread_cond_signal(&condQueue);
}
void* startThread(void* args) {
while (1) {
Task task;
pthread_mutex_lock(&mutexQueue);
while (taskCount == 0) {
pthread_cond_wait(&condQueue, &mutexQueue);
}
task = taskQueue[0];
int i;
for (i = 0; i < taskCount - 1; i++) {
taskQueue[i] = taskQueue[i + 1];
}
taskCount--;
pthread_mutex_unlock(&mutexQueue);
executeTask(&task);
}
}
int main(int argc, char* argv[]) {
pthread_t th[THREAD_NUM];
pthread_mutex_init(&mutexQueue, NULL);
pthread_cond_init(&condQueue, NULL);
int i;
int results[TASK_COUNT];
for (i = 0; i < THREAD_NUM; i++) {
if (pthread_create(&th[i], NULL, &startThread, NULL) != 0) {
perror("Failed to create the thread");
}
}
srand(time(NULL));
for (i = 0; i < TASK_COUNT; i++) {
Task t = {
.taskFunction = i % 2 == 0 ? &sum : &product,
.arg1 = rand() % 100,
.arg2 = rand() % 100,
.result = &results[i]
};
submitTask(t);
}
for (i = 0; i < THREAD_NUM; i++) {
if (pthread_join(th[i], NULL) != 0) {
perror("Failed to join the thread");
}
}
for (i = 0; i < TASK_COUNT; i++) {
printf("Result %d: %d
", i, results[i]);
}
pthread_mutex_destroy(&mutexQueue);
pthread_cond_destroy(&condQueue);
return 0;
}
is it correct for return value for task
Yes, that's also a solution. Good job!
You could also just store the result directly in the Task struct and then you wouldn't even need another array
Hello!
I'm from Brazil,
here we have severals good C programers, but, them generaly do not share knolegment,
so that's why I'm watching your videos,
congratulations for the good classes and don't stop, you are helping loads of people from all over the world.
Thankyou very mutch!
I finished the "Unix Threads in C" playlist, it was good, thanks
I like this kind of explanation which I compare to peeling bananas and slowly feeding it to babies. Thank you for sharing knowledge. As an experienced C programmer, watching all the thread videos in these channel gave me good refreshment of concepts in detail.
Thank you so much sir
Thank you for this playlist
Super nice and clean. Thank you !
Amazing video series and channel. Thanks so much for this!
Thank you :)
Thanks sir! It is helpful for us...
Hi! Your video series explain most concepts about multithreading, but you've missed one concept which is not even found on any websites. It is the use of multithreading dynamically. A program that creates multiple number of threads depending on the input of the user. Could you please make a video of that as well. Suppose a program needs to be created that prints numbers between 0 to 1000 but the threads are dynamic depending on the user input. So, it needs to be split into n numbers as users want it. How is it done? Thank you in advance.
Sure I will look into this
Great vid! I've managed to mostly port this over to Windows using its API, but I have a question not touched on here. What's the best way to keep track of when your threads are all complete? Say we have a huge physics simulation we're running, so we want to throw the work at a bunch of threads, but we don't want to continue on the main thread until all the work is complete. Would we simply use the same mutex and add a counter that we increment and decrement on job start/completion? then we simply sleep the main thread until this counter is 0?
Yes, or you could use a timeout when the job count goes to 0 and, once that happens, simply stop the process. You might need a separate thread for that
Thank you
First of all, thank you very much for your videos, they are excellent!
Would be really cool if you made a video talking about the problem of readers/writers, introducing the use of pthread_rwlock_t
Noted.
Say you have 2 or more threads running the same function at the same time. Is this a concern for race conditions? I’m trying to multithread a function that does some computation from global inputs, and sets it equal to a global output. The inputs and outputs are global arrays, but I’m sending it different index numbers. Would race conditions occur in this set up?
Thanks for the videos, they’re great.
No, this won't cause a race condition since the actual memory that is modifying is different
Would it be best practice to call free on the task object after the execute task function or will that cause other problems? thanks for the vid!
No. Since you don't know if that task object has been allocated dynamically or not. It's good practice to let the caller manage its own memory
Thank you for the videos.. they are excellent. While designing how do we normally fix the number of threads in a thread pool...
I usually just detect how many cores the computer I'm running from has and set it at that.
sir I would like to ask you what if lets say we created a number of threads and we would want to execute each function at certain time periods so we would have them waiting for certain signals would we still get benefit from using threadpools and the producer consumer logic??
The thread pools are specifically made to abstract when and how the jobs get executed... So, in this situation it would be wise to not use thread pools. Although, there might be some situations where this is useful
There is still an infinite loop in `startThread`, which never returns. Any solutions for this?
You can listen to a signal or, on a different thread, have a scanf that, when entering an option, closes the whole process
@@CodeVault thanks! Below `submitTask_done` is used to signal that all tasks have been submitted. Then, if `taskCount` equals 0 in the infinite loop in `startThread`, it will return NULL.
```
--- Thread_Pools_with_function_pointers_in_C.c 2024-11-02 15:33:30.508724954 +0100
+++ newer_version.c 2024-11-02 15:37:35.525364984 +0100
@@ -14,6 +14,7 @@
Task taskQueue[256];
int taskCount = 0;
+int submitTask_done = 0;
pthread_mutex_t mutexQueue;
pthread_cond_t condQueue;
@@ -51,6 +52,10 @@
pthread_mutex_lock(&mutexQueue);
while (taskCount == 0) {
+ if (submitTask_done) {
+ pthread_mutex_unlock(&mutexQueue);
+ return NULL;
+ }
pthread_cond_wait(&condQueue, &mutexQueue);
}
@@ -85,6 +90,7 @@
};
submitTask(t);
}
+ submitTask_done = 1;
for (i = 0; i < THREAD_NUM; i++) {
if (pthread_join(th[i], NULL) != 0) {
```
I tried to trace how the threads work by adding print statements and I noticed that in the end, the loop that calls pthread_join() on each thread in th[] does not completely execute. After entering the loop and reading the first join the program is stuck. What is causing this?
That's intended. pthread_join basically returns only after the thread you joined finished its execution (so effectively puts the main thread to sleep until then). This is so that you can wait for your threads to finish execution before stopping the whole process. Otherwise, you would end up calling return; on the main function in the main thread, stopping the process, which would also stop all the threads regardless if they are running or not
{
while (1) {
int time = 0;
Task task;
int found = 0;
// pthread_mutex_lock (&mutexQueue);
// while (taskCount == 0) {
// pthread_cond_wait (&condQueue, &mutexQueue);
// }
if (taskCount > 0) {
found = 1;
task = taskQueue[0];
for (int i = 0; i < taskCount - 1; i++) {
taskQueue[i] = taskQueue[i + 1];
}
taskCount--;
}
// pthread_mutex_unlock (&mutexQueue);
if (found == 1) {
executeTask (&task);
}
if (time == 0) {
return NULL;
}
}
}
I did not use pthread_mutex_lock and it worked and with return NULL the thread join worked ;)
Hi! I have been running tests using thread pools in order to provide accurate comparable timings when it comes to using high performance computing on an algorithm I've been playing around with (my masters thesis!) This code never reaches the return at the end of the main() function. The Pthread_Join() function appears to be the problem as the threads in the threadpool never return or call pthread_exit() in order to leave the while(1) loop, so it simply hangs on the join function. I understand that there needs to be a way to keep those threads alive long enough that they can finish their work without the main thread destroying them, but this solution doesn't allow the program to end, and the tests that I need to run need to allow for multiple different sized thread pools, so I need to be able to destroy and recreate pools multiple times in one run of the executable. I've looked into my own solutions to this problem, but to no avail. Is there a graceful way to get the threads off the cond_wait and join without having to call pthread_cancel()?
A simple solution would be to add a special task to the queue that makes the threads exit. You can send it from the main thread when you finished processing what you wanted. Another solution would be to remove the while(1) in the loops and just have them execute a predefined number of tasks
First, great videos man, you explain so well and carefully this topic. Thank You so much.
I got a question, I know that in the video you use an example of random numbers that add to each other, but in a program were I have to print the output (result) in an ordered way, how can I do that without serializing the program?. It doesn't matter the order of the execution of the threads, I only want the output to be in an ordered way. Thank you!
Uhmm, I suppose if you want just your output to be ordered in some way you could simply sort it (in an array) based on some index after everything is done (or on every insertion). Either that or you give each thread a unique index where they should store the results
Hello!
This playlist is really great thank you!
I have a question how can I actually avoid using global variables, like int taskCount and Task taskQueue?
You could just pass an address to a variable (like taskQueue) when initializing each thread which can be stored in the main's function memory
Thank you for the video. Isn't there any better way to update taskQueue array not by shifting the tasks every time? It takes O(N) time for every visit.
Take a look at a circular buffer, it's O(1)
@ It's not a circular queue, it always takes 0 index value after shifting.
for (i = 0; i < taskCount - 1; i++) {
taskQueue[i] = taskQueue[i + 1];
}
It may not be an issue if taskCount is small otherwise it costs some time.
If you implement the queue on a linked list and not on an array, the complexity when updating should be O(1). Maybe you also need to store both head and tail of the list.
@@CodeVault Thank you , linked list can be the right solution as you said. I was thinking circular queue with an array but it may be also concerned for overflow situation.
Ball3r
Love your videos !
first comment !! :-D