A thread pool is a collection of pre-created threads that continuously wait for tasks to execute, providing efficient concurrent processing by reusing threads instead of creating and destroying them repeatedly; the implementation uses a queue to store tasks, a mutex for synchronization, and a condition variable to notify threads when new tasks arrive, allowing multiple tasks to be processed in parallel while controlling the maximum number of concurrent threads based on system capabilities.
Thread Pool In C++: Efficient Multithreading Implementation Guide
Added:so hello guys this is rup and you're watching CBB video series on C++ and this is about thread pool so I know this is a most AED video so let's do [Music] it so before going further let's try to understand what is thread pool and why do you need that so thread pool is something you will have I mean the name says thread pool you will have pool where you will have many threads it's very simple and those threads will be always running and waiting for you to give them the task it's like uh if you go to hotel and if it is a big hotel you will see like so many waiters are actually waiting for you to order they will be standing in some queue or somewhere and they will come and attend you right so similarly in thread pool also those threads will be simply waiting for your task and the moment you give them the task they will start executing that so your application in such a way that it can spawn many threads at any time okay so because it wants to run those task in parallel so it will have to spawn a thread okay so you cannot just randomly create let's suppose you have 10 tasks 20 tasks maybe thousand tasks available for now you cannot just simply fire 10,000 or th000 threads it will choke up your whole system so that's not the correct way so if you will have a thread pool where you can schedule the task like okay I will assign these task to a thread pool now thread pool's task is to pick the task from the queue and assign it to different different threads so like how many threads it have it will schedule those task to those threads and you have the control to create n number of threads in any thread pool so if your system supports like eight threads simultaneously if it has eight core it will be good ide to have a thread pool which will have eight threads in that and not only that actually if you are creating thread at random time and then once that job is done you are destroying the thread then this creation of the thread and destroying of the thread is like a wastage right if you can somehow create a thread and then use that thread all the time and once your application is terminating or getting closed that time you terminate all those threads so with this way you will not have to create threads again and again and again and you will end up saving so much of time also so there can to be n number of benefits of this thread pool we have just learned about few basic ones so let's now try to understand what you really need to implement thread pool so first I will draw uh a conceptual diagram or whatever diagram I will draw here I don't know what is that called but it will help you to understand the entire thing okay let's see we have so this is threadpool object so when you are creating thread pool let's say this is TP is the class name and then pool pool is the object name and here you will say let's say four threads so inside main function if you're writing something like this it should end up creating something like this I'll tell you what it is so T1 T2 T3 T4 they all are threads they all are continuously running okay I'll just say continuously running there is a loop here they all are running and they all are see they are all trying to access this Q where we will have ta task one task 2 task three and N number of task because it's a q so they all will try to access this queue so that they can get the job and start running those jobs or task but there is this mutex here because this is a single Q between multiple threads we all know that we have to guard it right so we are guarding it with mutex so only one guy is allowed to modify this queue and and how this whole thingy will work let's say T1 is able to get the mutex and T1 took this task one now T1 will have to remove this task from the queue and then only it can execute okay because it cannot start executing if the task is already in the queue it will have to remove the task and then it will start executing that because execution of the task can take maybe quite long time for that we cannot block this Q because other threads can take their job right so they will just quickly take their job and release the mutex this is the thread pool now let's quickly see what interface you need for this thread pool so if this is L here this is pool so you want a mechanism where you can push the job inside the pool so we know that okay pool is created with four threads so we'll see how we'll create these threads in Constructor of the thread pool and we'll destroy all these threads in the destructor of the thread pool so I was talking about pushing the job right so that pushing we will say NQ because it is a q we will say NQ the jobs so you need this mechanism to push the job and here itself the inner part of this NQ would be to signal that okay some task have come wake up now you have to start the execution because they cannot keep on checking some task have come or not otherwise that would be pooling and it will waste so much of resources so I mean CPU resources it will work again and again and check if something have come or not something have come or not no we'll not do like that we'll ask these threads to sleep so that it will not waste so much of resource and the moment we enq something we'll ask we'll send a signal to any one of these threads that you can wake up and start picking the jobs so NQ is done signaling is done signaling is part of the NQ okay and second thing is you need a mutex which will actually guard your Q so you need third point which is Q this will contain all the task and accessing this Q will be guarded with meex and fourth thing is like very implicit but still I will tell you it's a vector of threads you'll have to contain these threads in some vector or container right so this is also required so let's look at the code now and bear with me guys I'll definitely explain you this code so this is the object I was talking about this is thread pool we are creating this object we are telling that how many threads we want we are telling we want four threads these are just some print of messages and this is the job pushing task so see we have this pool here and we are ening meaning we are pushing the job inside the que and this job is in form of Lambda if you don't know what is Lambda functions please go ahead and watch my previous videos and the best way is just search Lambda function with my channel name CBB nerds Lambda function you'll get it so these are kind of a function pointer you are pushing to the que and those threads will pull out these functions and start executing these functions and here I'm printing just thread ID and this count and we'll simulate that task is taking 1 second to complete okay and the moment we are finished pushing those jobs into the queue we will start doing our own stuff like we will not wait for all these things to get completed because we can push thousands and thousands of job for all these four threads and scheduler will actually take care we will not wait for this thread pool to actually finish all those, tasks and then we go ahead no so that's how this is concurrent operation so NQ is done now let's see how the NQ looks like so I told you right we are getting this task here and we are taking those task as R value reference refence I know I have not explained this r value reference maybe I don't know I'm not quite sure but it's like you just try to understand you're sending a function and this is a perfect forwarding this is trying to take that function as it is whatever parameter you have passed there and it will forward to this as it is that's why we are doing all these things now look at the main part we have this lock mutex which is first trying to lock it and then only we are accessing this tasks Q so this is the Q where we are EMP placing this task function what we have sent from there and then we'll just quickly unlock and now this is the point I was telling you right you have to signal to the threads that wake up I have just pushed a task so this condition variable will help you to notify all those threads that okay something have come start executing so this is done we know how to NQ the task let's let's go and see how to actually create the object of thread pool this is fun so you remember you sent four number right so that four number is coming here number of threads so we'll have to create in a loop right like if you are asking for eight threads nine threads 10 threads so that will have to go in a loop in a loop what we are doing we have this workers Vector this Vector is nothing but I'll show you that it will store your threads see this is the worker and it is storing threads in it okay so this is worker so M Place B we are actually creating the thread inside the vector itself and we are telling that attach that thread with this Lambda function so whatever is selected is a thread and it will be pushed back into this Vector from 0 to three meaning four times now let's see what is happening inside these threads and yeah now as you are done executing this whole thing you have have four threads running and let's see what is their state see it will come inside we have this infinite for Loop right and then we will try to acquire the lock and we'll wait here on that lock if we get false from here so this is the condition for conditional weight if you don't know what is conditional weight how it works I have video for that also it is really a GameChanger thing okay so go ahead and watch that also if you don't know this so it will execute this tiny little function this is also lamb it will execute this and check whether I should wait or go ahead and it will decide on whatever it returns so stop is initially false if you see here so this is false and this task. empty thing will return true and we have negation here so this is also false so in the end it will return false remember this we have not enced the task yet we have just created the thread pool only so all the four threads will wait here now let's go to the place where we are enqing the whole thing so I will take you there yeah we started enqing and let's say we pushed this first job now it will come here and we'll try to lock the mutex as all threads are actually sleeping this can be logged and we'll push this first job and unlock the mutex and tell I know four threads are actually waiting for this condition variable I will notify any one of them so it's not our hand which one will get notified but we are telling notify anyone so anyone will get wake up and it will check this condition again because this can be a spurious wake up also which is like a false thing so in that case stop is still false but this guy task. empty is true no so it is false false negation true so this time it will go true here and it will come inside this is false so it will not go here this condition is to terminate the the threads okay I will explain this also in the end so this won't execute because false is I mean stop is false it will go ahead and remove so this is like moving out the front of the task meaning if it is Q you know that Q is always access from the front and stack is always exis from the top so if it is Q then we'll take the front and we'll say move it out basically it will move the content from there to this variable so I have written also this right extract the task from the task list so we are extracting it and then we are saying remove this task from the task list so we have the task available inside this function I mean this variable and we have removed this task from this task list now we'll unlock this and this is where the whole thing is happening we are now executing this task so this task is actually executable that's why we are able to apply this bracket here and we are actually executing the task here and see by the moment we are executing the task it is obviously possible that there are many many many tasks coming let them come I'm ready because I have just released the lock here they can acquire the lock and start doing their job I mean all those different threads will do their job now while I'm running this task because this task can take maybe 5 days 10 days or 15 days or 5 minutes 5 Seconds doesn't matter we are not blocking anything cool right and once you are done you will again go and loop and try to lock this and the whole story will go again and again for this particular thread and for all the threads so now you can imagine right how it is going to work I not just explained this line here let's see even that also so this line will come in the destructor of the threads so let's say okay let's let's go first to the main function let's say you have cued eight jobs and you started doing your own job and then it is hitting this return zero the moment it is going to hit return zero it will try to deallocate this pool object and see what is happening in the destructor you might be missing the joining and stuff right so this is the place where you will actually join all those threads so this is kind of a waiting for those threads to finish so now destruction is happening you will acquire the lock and see now you're telling stop is equal to true and lock is now unlocked you will notify all the threads and then you will join or wait for them to do their job and complete it and then the whole thread pull object will get destroyed now I know you need so many of prior knowledge like what is condition variable how to push threads into the vector and what is actually this this whole Q thingy here because maybe you might not be aware of what is this STD Q here and what is this function they are not big task to actually understand you will Google I mean you will search on YouTube you will get each and everything maybe you will not get this STD function in my channel I mean but if you want to understand hypothetically what it is doing it is telling that I am a q data structure and I will contain function pointers so these are task right are pushing Lambda functions into this task Q so its type has to be somehow function right so that's how you are doing it now let's see how those threads are stopping when this stop is true okay let's see that so let's say every thread was actually doing some job or waiting for something for Simplicity we'll just believe that okay everything was done and they all are waiting for new job let's pick that scenario first so in that case as we have notified all see notify sorry not this one notify all if you remember uh where is that here it is we are saying notify all right so all the threads will get signal and it's like all the threads will get true here because stop is true now this if stop is true yes it is true and task. Mt is true yes there is no task then we'll return so this return is for all the threads because the same function is actually used for all the four threads now it's the time to actually execute it let's execute it and let's try to understand what is happening here so it says thread P created NQ assigned some task so we started assigning the task and you saw that there was a halt here right let me rerun this again and I will quickly put one more enter so these four bunches were actually running at the same time and then these four started running at the same time so if you notice here we have only four threads that's why these four jobs were automatically running at the same time and they all waited for almost 1 seconds because they all are running at the same time and they will simulate the behavior that they all took 1 second at the same time meaning collectively it will be just 1 second only because they all started at the same time and then these threads will start getting executing so don't think that it is written here so it is printing just before it is getting nced here no it is not printed here it is printed when this piece of code is running try to understand this this is the key point of this whole thing you are enqing this function here you are not running this function here you are giving this function to the pool that okay when some thread is available give this function to those threads and those threads will run the this function so these executions are basically from those threads cool right let me change this number of threads let's say we will have two threads in the pool let me quickly compile this and now if we'll run this you'll see two threads are running at the same time see two two two that's it I'll hit enter when they are waiting for 1 second okay then it will make uh a good graphical thing see these these two were running at the same time these two and these two cool right now let's say you might go little crazy or maybe you will say okay now I will have eight threads and 40 jobs so let's say 40 jobs I'll compile this and execute it now just see these these these these these and yeah see all are in the form of 88 jobs running at the same time and see their execution order is not in sequence so they are actually pure synchronous and this is nothing but a thread ID here so if you notice the same thread ID 36B you'll get it here also see this is 36 b0 this is 36 b0 we are reusing these threads to do our job this is the beauty I mean when I learned this it was so beautiful and I was so so happy about it and I just suddenly started feeling that okay I know so much so this is really good I mean it will give you a good feeling I know and these these lines these enters I am putting so that I can give you the perfect simulation because if I won't do that see it will be just one after another see and you'll be confused like which one ran at one time so if I'll run this and I'll hit enter hit enter hit enter enter then it will give you the simulation okay these threads were running at the same time then only I could give the enter Because all will wait for one second cool right so I know I'll sum up this video guys I know this is like very big video I'm so sorry if you guys got to wait a lot but I feel it is worth it so thanks for watching guys I'll see you in the next videos bye-bye take care
Up Next

Multicore Game Development: C++11 Practices
@CppCon
52.7K views•2014-10-23

BitTorrent Protocol Explained: Piece Selection & Peer Choking
@StevenGordonAU
481 views•2013-02-22

HTTP Requests Explained: GET, POST, PUT, DELETE
@codecademy
103.1K views•2021-10-07

Enigma Machine Mechanics: WWII Encryption Explained
@JaredOwen
13.2M views•2021-12-11
Related Study Plans & Knowledge Roadmaps
Structured learning paths in Computer Science












![Multithreading in Cpp [024] - std::condition_variable](https://i.ytimg.com/vi/uq5lc_y2op0/maxresdefault.jpg)











![[KAIST CS492C, 2020 Fall] Other lock-free data structures](https://i.ytimg.com/vi/p_vuhwMPHD8/maxresdefault.jpg)








![Lock-free programming with modern C++ - Timur Doumler [ACCU 2017]](https://i.ytimg.com/vi_webp/qdrp6k4rcP4/maxresdefault.webp)




