I started teaching myself C a couple of months ago in order to program a Raspberry Pi to 'upgrade' an older car. Your videos have been completely awesome. This one in particular has helped me to understand how I need to lay out and architect my program. Please keep up the wonderful tutorials, they are greatly appreciated.
As a professional computer programmer, I know the C programming language, but I've never heard of anyone using it to 'upgrade' an older car. I don't even knew that such a thing was possible. Please tell me more about your project.
@@konstantinrebrov675 the project has been on hold for a while, life has gotten in the way. But the basic idea is to use a CAN Bus adapter with an SBC. The reading of data from the CAN Bus will be handled in C, and the output can be sent to a web based display mounted in the console. I'm thinking about wiring a couple of thermometers up for cabin temp input, then modifying the manual AC/heater controls with servos that are controlled by the SBC. That would 'upgrade' the climate control to be automatic. Just program in a web UI on the touch screen mounted in the console, set the temp that you want and let the programming handle the controls. I have similar plans for stereo control, seat position, etc. Basically, all the things that you find in modern cars. Taken to the extreme, you can replace window controls with LIN Bus, and even control headlights/tail lights. That's going to take a lot more time and will probably require an RTOS based controller or custom firmware for a microcontroller. I'm not there yet.
Really awesome series. It helped me to understand multi-threading concepts. One question, is there a common rule to say, when to use condition_variables and when to use a semaphores ? Only advantage of condition variables over semaphores, which I can think of is that with condition variables there is a API to broadcast the signals, I guess, semaphore doesn't have that mechanism.
Basically semaphores are a more rudimentary component for synchronization, compared to the rest. You can implement condition variables, mutexes, barriers and other such objects with just semaphores, but they are there because people need them often. So, if your use case is similar to what I showed in the video, the best thing is to use those higher level ones (mutexes, barriers and condition variables). If you need some more custom or more specific you can use semaphores to basically build your own synchronization objects
ive seen thread pools used for servers where a connection is made and the pool is leveraged to activate a worker thread to process the incomming data but they always activate a thrad based on a connection being initiated and close the socket when that one job is completed. what if you dont want to CLOSE the socket but want to activate a thread based on incoming data ?
okok after one thread got the task, the release the lock for other threads to get the tasks. But at the same time, we want every tasks immediately execute after they got the task. So execute Task should be available at any time. (even if 2 or more thread got their tasks.)
I have a question! How to wait when the pool is full, like we can deal with max 256 task at time, I got a segment fault when I tryed to run (intencionally) 1000 task. Is possible to wait until it have an empty slot ? Thank you!
Yes, just check if taskCount is too big in submitTask. If it is, just pthread_cond_wait, basically the same as in startThread but with a different condition
Thank you for the video, it helps me understand the thread pool concept. BTW why mutex protection is needed in submitTask() function? It's called only by main thread, so I don't think it's needed.
Let me try to explain (before Author do that better...): In main thread with "submitTask" function you increment "taskCount" variable, but at the same time another thread can decremant "taskCount" variable in "startThread" function. It's very risky to let them doing this at the same time. An idea behind Threads pool means that you can add task at any time during program is running. You can ie. start For loop which adds 100000 tasks (incrementing "taskCount" variable at each iteration of For loop) and at moment when you begin adding, thread running "startThread" function starting to execute task decrementing "taskCount" variable.
how can you get the program to exit? ---I initially asked this question a few minutes ago but figured it out. If anyone else has this same question you add an if statement right after the if (found ==1) -> executeTask(&task); You add an if statement mine was: if(taskCount == 0) { break; }
Not very ideal. Because the tasks could be dynamically created so at some point the task queue would be empty but a new task could be created in the next moments. Some sort of flag that signals the end of the task creation I believe would be better. So you check if (taskCount == 0 && creationFinishe == 1){ break; } and the flag could be a global variable.
@Code Vault. Why do you have to gaurd the submitTask using mutex in this case. I see that it (submit task) is performed by main thread . all the elements are added in queue before even the threads are created. please clarify if we really need to gaurd the submit task code using mutex.
Great video but I noticed that the program never ends by itself and it needs ctrl+c to end. I've taken the code for a similar project and it can't move past the pthread_join. How can I change that?
You could implement another thread that checks if there are tasks still executing (or to be executed) and, if not, just end the whole program. You could start this thread after adding all the tasks
It will return once the thread stops executing. In this specific example the threads never stop (they are all basically executing an infinite loop). As a homework, you could try creating a mechanism to stop the threads after you press a key on the keyboard or after some idle time
How will the threads join at the end if you only submit one task and the rest of the threads are waiting on the conditional variable? Will the program not hang?
It will hang forever. But, really, you can always create a mechanism where, in the main thread, you wait for some input (or after some time elapsed and nothing got executed) and simply stop the process
Hello! How do I exit my threads when there are no more tasks to run? It looks like the program you provided needs Ctrl + C before the program ends? Thank you in advance!
Hmm... yeah, the program technically never stops since it forever waits for tasks to execute. You could have maybe a variable that stores the seconds elapsed since you last executed a task and a thread that checks that variable every second. Then, if it sees that let's say 30 seconds elapsed, it sets a special variable to true, broadcasts to all threads to wake up and terminate their execution. You'll also have to change the while condition for each waiting thread to check for that special variable. There are probably other ways to do this, but this the first thing that comes to mind
What do I do if all threads are at pthread_cond_wait? Is there any way for me to notice that? If tried to implement a counter combined with a leave boolean, but I wasn't able to make something like that work :/
Logically, you should have a thread that triggers the pthread_cond_signal or broadcast. You can't have all threads waiting... Unfortunately, I don't think there's a way to check if all threads are waiting though
Hi mate ! I'm following along with you and I see you use camelCase to declare your variables. Did you recommend camelCase for C too, because I use it when coding in Java. In my examples I'm using snake_case what do you think about ? Thank you!
I'm just used to camelCase but I think snake_case is the more widely adopted version in C. I think you should use whatever you think is best as long as you don't mix them up throughout the project
No. If you use signal, only one of the threads wakes up. If you use broadcast instead, then all the threads wake up (although, in most situation, the result is the same), it's just much less efficient with broadcast
@@CodeVault Yes , I saw it was discussed also in other comments . Thank you for your time , love your videos , hope you make more , like for embeeded systems .
Yeah, that's right in this case. In a production environment I think there should be a way to stop the threads properly and have those pthread_join calls executed
Usually, yes. If you want to use the full power of your CPU if doing some CPU intensive task then starting the same number of threads as your core should be perfect.
I tried creating this tutorial on my own but in my case(where task count is 10) all the tasks are allotted to thread 0 and the other thread did not get any task Edit - It is working fine after some delay in executing function
@@CodeVault Hey yes I have watched that video but in a thread Pool scenario can we check about the process id? as in which thread takes which task, or it's difficult to know about it
@@CodeVault C++ hasn't its own thread-pool, but it would be nice if the semantics of thread and jthread simply would be mapped to a pool if adviced by the developer.
@@CodeVault ==75== Possible data race during write of size 1 at 0x527158C by thread #2 ==75== Locks held: none ==75== at 0x48488A6: mempcpy (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_helgrind-amd64-linux.so) ==75== by 0x490D7B1: _IO_new_file_xsputn (fileops.c:1236) ==75== by 0x490D7B1: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1197) ==75== by 0x48F592C: __vfprintf_internal (vfprintf-internal.c:1687) ==75== by 0x48DFEBE: printf (printf.c:33) ==75== by 0x109397: executeTask (in /mnt/c/Users/gabri/github/SystemNear/mdu/a.out) ==75== by 0x1094CA: startThread (in /mnt/c/Users/gabri/github/SystemNear/mdu/a.out) ==75== by 0x4842B1A: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_helgrind-amd64-linux.so) ==75== by 0x4861608: start_thread (pthread_create.c:477) ==75== by 0x499D102: clone (clone.S:95)
executeTask is made to be executed in parallel with other tasks. It isn't a problem because the code that is calling executeTask should never read/write the same task. Sure, a mutex can be added per task in this codebase but I think that's beyond the scope of this video.
THE FU**ING GOAT OF programming with mutexes, locks, and threads in C. You carries me through my assignments, thanks a lot!!!
I'm currently a computer science student and your tutorials are Golden! thank you very much
I started teaching myself C a couple of months ago in order to program a Raspberry Pi to 'upgrade' an older car. Your videos have been completely awesome. This one in particular has helped me to understand how I need to lay out and architect my program. Please keep up the wonderful tutorials, they are greatly appreciated.
Nice you can upgrade your car in my country that's impossible due to a mountain of regulations and paperwork and its illegal in some cases
@@chromiumos4114 That's the case here too for newer models. But anything older than '96 is fair game in most areas.
As a professional computer programmer, I know the C programming language, but I've never heard of anyone using it to 'upgrade' an older car. I don't even knew that such a thing was possible. Please tell me more about your project.
@@konstantinrebrov675 the project has been on hold for a while, life has gotten in the way. But the basic idea is to use a CAN Bus adapter with an SBC. The reading of data from the CAN Bus will be handled in C, and the output can be sent to a web based display mounted in the console. I'm thinking about wiring a couple of thermometers up for cabin temp input, then modifying the manual AC/heater controls with servos that are controlled by the SBC. That would 'upgrade' the climate control to be automatic. Just program in a web UI on the touch screen mounted in the console, set the temp that you want and let the programming handle the controls. I have similar plans for stereo control, seat position, etc. Basically, all the things that you find in modern cars. Taken to the extreme, you can replace window controls with LIN Bus, and even control headlights/tail lights. That's going to take a lot more time and will probably require an RTOS based controller or custom firmware for a microcontroller. I'm not there yet.
Every time I watch your videos I get instant relief lmao
You explained TP in very simple way , awesome..its very difficult to deliver tough things in simple way, but you did great job :)
Best C videos by far, really helped out in my systems programming course!
omg...your videos are so amazing and the topics are really good. Keep posting. thanks
Great job do not stop you are doing wonders
Thank you for your guide! Now I can finish my coursework
Great videos man. Keep up the great work.
Thank you! really like your way of teaching
Fantastic explanation, pace, content.
Amazing! Thanks for taking the time.
Thank you man, you I really got your way of explanation. You're awesome!
Really awesome series. It helped me to understand multi-threading concepts. One question, is there a common rule to say, when to use condition_variables and when to use a semaphores ? Only advantage of condition variables over semaphores, which I can think of is that with condition variables there is a API to broadcast the signals, I guess, semaphore doesn't have that mechanism.
Basically semaphores are a more rudimentary component for synchronization, compared to the rest. You can implement condition variables, mutexes, barriers and other such objects with just semaphores, but they are there because people need them often.
So, if your use case is similar to what I showed in the video, the best thing is to use those higher level ones (mutexes, barriers and condition variables). If you need some more custom or more specific you can use semaphores to basically build your own synchronization objects
ive seen thread pools used for servers where a connection is made and the pool is leveraged to activate a worker thread to process the incomming data but they always activate a thrad based on a connection being initiated and close the socket when that one job is completed. what if you dont want to CLOSE the socket but want to activate a thread based on incoming data ?
Thanks! Very good lesson!
ありがとうございます!
okok after one thread got the task, the release the lock for other threads to get the tasks. But at the same time, we want every tasks immediately execute after they got the task. So execute Task should be available at any time. (even if 2 or more thread got their tasks.)
mutex here to protect the shared memory (Task queue) 14:36
I have a question! How to wait when the pool is full, like we can deal with max 256 task at time, I got a segment fault when I tryed to run (intencionally) 1000 task. Is possible to wait until it have an empty slot ? Thank you!
Yes, just check if taskCount is too big in submitTask. If it is, just pthread_cond_wait, basically the same as in startThread but with a different condition
@@CodeVault Humm, thank you !!!
Thank you for the video, it helps me understand the thread pool concept. BTW why mutex protection is needed in submitTask() function? It's called only by main thread, so I don't think it's needed.
Let me try to explain (before Author do that better...):
In main thread with "submitTask" function you increment "taskCount" variable, but at the same time another thread can decremant "taskCount" variable in "startThread" function. It's very risky to let them doing this at the same time.
An idea behind Threads pool means that you can add task at any time during program is running. You can ie. start For loop which adds 100000 tasks (incrementing "taskCount" variable at each iteration of For loop) and at moment when you begin adding, thread running "startThread" function starting to execute task decrementing "taskCount" variable.
@@mariuszk8339 Oh I missed taskCount is shared by main and other threads, thanks.
good bro, very helpful thanks
how can you get the program to exit?
---I initially asked this question a few minutes ago but figured it out. If anyone else has this same question you add an if statement right after the if (found ==1) -> executeTask(&task); You add an if statement mine was:
if(taskCount == 0) {
break;
}
Not very ideal. Because the tasks could be dynamically created so at some point the task queue would be empty but a new task could be created in the next moments. Some sort of flag that signals the end of the task creation I believe would be better. So you check
if (taskCount == 0 && creationFinishe == 1){
break;
}
and the flag could be a global variable.
well explained. thanks!
literally no reason for disliking this video. Hence No dislikes
very helpful!
Thank you!
19:31 thread works only when it gets a task, otherwise wait and release lock
Thankyou sir!
also make sure 13:21 each thread would not executeTask when they have no task! (found ==1)
Hello, I love this tutorial in to thread pools. Can you also do a video on a fork-join threadpool or a work stealing threadpool? Thank you!
There's this video on the topic: code-vault.net/lesson/w1h356t5vg:1610029047572
@Code Vault. Why do you have to gaurd the submitTask using mutex in this case. I see that it (submit task) is performed by main thread . all the elements are added in queue before even the threads are created. please clarify if we really need to gaurd the submit task code using mutex.
Because startThread reads from the taskQueue which is NOT executed in the main thread
Thank you so much!
Great video but I noticed that the program never ends by itself and it needs ctrl+c to end. I've taken the code for a similar project and it can't move past the pthread_join. How can I change that?
You could implement another thread that checks if there are tasks still executing (or to be executed) and, if not, just end the whole program. You could start this thread after adding all the tasks
thanks for the video. one question though! why pthread_join doesnt return? I tried to printf a msg after pthread_join but the line is never executed
It will return once the thread stops executing. In this specific example the threads never stop (they are all basically executing an infinite loop). As a homework, you could try creating a mechanism to stop the threads after you press a key on the keyboard or after some idle time
How will the threads join at the end if you only submit one task and the rest of the threads are waiting on the conditional variable? Will the program not hang?
It will hang forever. But, really, you can always create a mechanism where, in the main thread, you wait for some input (or after some time elapsed and nothing got executed) and simply stop the process
Hello! How do I exit my threads when there are no more tasks to run? It looks like the program you provided needs Ctrl + C before the program ends? Thank you in advance!
Hmm... yeah, the program technically never stops since it forever waits for tasks to execute.
You could have maybe a variable that stores the seconds elapsed since you last executed a task and a thread that checks that variable every second. Then, if it sees that let's say 30 seconds elapsed, it sets a special variable to true, broadcasts to all threads to wake up and terminate their execution. You'll also have to change the while condition for each waiting thread to check for that special variable.
There are probably other ways to do this, but this the first thing that comes to mind
What do I do if all threads are at pthread_cond_wait? Is there any way for me to notice that?
If tried to implement a counter combined with a leave boolean, but I wasn't able to make something like that work :/
Logically, you should have a thread that triggers the pthread_cond_signal or broadcast. You can't have all threads waiting... Unfortunately, I don't think there's a way to check if all threads are waiting though
Thank you
Hi mate ! I'm following along with you and I see you use camelCase to declare your variables. Did you recommend camelCase for C too, because I use it when coding in Java. In my examples I'm using snake_case what do you think about ? Thank you!
I'm just used to camelCase but I think snake_case is the more widely adopted version in C. I think you should use whatever you think is best as long as you don't mix them up throughout the project
submittask() only executed by main thread. Then do we need mutex lock in it? Is it still critical section?
Yes, because while we execute submitTask another thread could take a task from the task array creating a race condition
if multiple threads are waiting for a signal, and i signaled an condition variable once, will those multiple threads execute at the same time?
No. If you use signal, only one of the threads wakes up. If you use broadcast instead, then all the threads wake up (although, in most situation, the result is the same), it's just much less efficient with broadcast
Great video . Wanted to ask , is the function submitTask threaded ? Are all threads execute it , or only the main thread ?
Well, submitTask is only executed in main but it could be executed by any thread since the array it's working with, is guarded by a mutex
@@CodeVault Yes , I saw it was discussed also in other comments . Thank you for your time , love your videos , hope you make more , like for embeeded systems .
Do a networking tutorial pls
Hey
Why you dont use a semaphore here?
It's just preference, you can do it with a semaphore as well
@@CodeVault so there is no functional reason to not use a semaphore, maybe over the number of threads or tasks?
Is it correct to say that your join calls in the main thread wouldn't do anything since your threads run in an infinite loop?
Yeah, that's right in this case. In a production environment I think there should be a way to stop the threads properly and have those pthread_join calls executed
thank you for the tutorial!
4 threads, because 4 cores?
Does this mean a good choice for the number of threads is the number of cores?
Usually, yes. If you want to use the full power of your CPU if doing some CPU intensive task then starting the same number of threads as your core should be perfect.
I tried creating this tutorial on my own but in my case(where task count is 10) all the tasks are allotted to thread 0 and the other thread did not get any task
Edit - It is working fine after some delay in executing function
Hey
how can we know which thread executes which task?
Kindly help me in this
I do talk about pthread_self and thread ids here: code-vault.net/lesson/18ec1942c2da46840693efe9b5210e1b
@@CodeVault Hey yes I have watched that video but in a thread Pool scenario can we check about the process id? as in which thread takes which task, or it's difficult to know about it
You can get the process id using getpid()
Is this is with respect to 64 bit machine? Does the machine type matters?
In this example, the architecture shouldn't matter
This looks rather rudiementary compared to a C++ thread-pool with a C++11 function-object queue.
Yes, if the video was about C++ then I would recommend using C++'s thread-pools but here we're working in C
@@CodeVault C++ hasn't its own thread-pool, but it would be nice if the semantics of thread and jthread simply would be mapped to a pool if adviced by the developer.
Just ran this with helgrind tool and it complains about several data races.
Where are the data races? Can you share the output, please?
@@CodeVault ==75== Possible data race during write of size 1 at 0x527158C by thread #2
==75== Locks held: none
==75== at 0x48488A6: mempcpy (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_helgrind-amd64-linux.so)
==75== by 0x490D7B1: _IO_new_file_xsputn (fileops.c:1236)
==75== by 0x490D7B1: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1197)
==75== by 0x48F592C: __vfprintf_internal (vfprintf-internal.c:1687)
==75== by 0x48DFEBE: printf (printf.c:33)
==75== by 0x109397: executeTask (in /mnt/c/Users/gabri/github/SystemNear/mdu/a.out)
==75== by 0x1094CA: startThread (in /mnt/c/Users/gabri/github/SystemNear/mdu/a.out)
==75== by 0x4842B1A: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_helgrind-amd64-linux.so)
==75== by 0x4861608: start_thread (pthread_create.c:477)
==75== by 0x499D102: clone (clone.S:95)
Isn't it a problem that in executeTask, several threads could be trying to read/write the same task?
executeTask is made to be executed in parallel with other tasks. It isn't a problem because the code that is calling executeTask should never read/write the same task. Sure, a mutex can be added per task in this codebase but I think that's beyond the scope of this video.
❤
how to run join these threads here
You could listen to some keyboard input or, after a long time of waiting for a task, just end the whole process
while all tasks run complete, [pthread_cond_wait(&condQueue, &mutexQueue);] will wait forever ,the program will never exit.
That's true. You can make a mechanism that, if, after 30 seconds, no task has been executed, you terminate the program. Or you could just use SIGTERM
THE FU**ING GOAT OF programming with mutexes, locks, and threads in C. You carries me through my assignments, thanks a lot!!!
Thank you so much!