Welcome to StackOverflow. I am fairly new to threading in C++ myself so I'm not familiar with the best libraries and techniques, but I can share at least a little about the basics I do know, and hopefully that gives you a feel of where to go from there.
If I understand correctly I believe you question mainly revolves around join()
so I'll start there.
Calling join()
is how you wait for a thread to join before moving on, but you don't have to do that as soon as you create one or it would be pretty pointless. You can let the thread go on its own merry way and it will end when it is done without any further input from the main thread (please correct me I am mistaken).
The important thing about join()
is that you call it on all the threads to wait for them before exiting the program (or otherwise aborting them somehow, safely of course). Otherwise they will continue running even after main() returns and will cause issues when they try to access memory as they are no longer attached to a running process. Another potential use might be to have a few worker threads match up at certain checkpoints in a calculation to share results before grabbing the next chunk of work.
Hope that helps. I had a few more thoughts though that I thought I would share in case you or some future reader aren't familiar with some of the other concepts involved in this example.
You don't indicate whether you have an way in mind for keeping tracking of the times and sharing them between threads, so so I'll just throw out a quick tip:
Lock your buffer before you add or pop from it.
Doing so is important in order to avoid race conditions where one thread could be trying to pop something off while the other is adding and causing weird issues to arise, especially if you end up using something like set from the standard library which sorts and ensures you only have one copy of any given element upon insertion.
If you aren't familiar with locking mechanisms then you could find examples of using Mutexes and Semaphores in C++, or do a search for 'locking' or 'Synchronization Objects'. You may consider the humble Mutex from the standard library.
As far as actually creating the threads, a couple things come to mind. One thought is using thread pools. There are several libraries out there for handling threading pools, with one such example being Apple's open source Grand Central Dispatch (commonly known as libdispatch) which can be used on Linux for sure, but for Windows you would want to look up something else (I'm not that familiar with the Windows platform unfortunately). They manage the life cycles of the threads you are and are not using so they could potentially help. Again, being a bit new to this myself I'm not 100% sure that would be the best thing for you, especially since you have other parts of the project to work out still, but it may be worth looking in to.
Even without using thread pools (say you use pthreads) I don't think you need to worry too much about starting a bunch of threads on your own as long as you put some reasonable limit on it (how much is reasonable I'm not sure but if you check out Activity Monitor in macOS or Task Manager in Windows or TOP in Linux you will see that at any given time many programs on your machine may be rocking quite a few threads-right now I have 5090 threads running and 327 processes. That's about 15.5 threads per process. Some process go much higher than that).
Hope something in there helps.