Why do I need a threading model?
Remember a few years ago, when I wrote the high-precision algorithm, because it required a thread-safe background (to save some information), then manually wrote a thread local storage (TLS) (although, later because of the calculation model changed, deprecated); later, because of the memory pool needs, also manually write a thread local storage (TLS) Well, so that in the same library, there are two sets of the same TLS, so, realize what is wrong.
Not only is the code repetitive (not many repetitions), but more importantly, TLS should be a feature of the threading model itself, but, unfortunately, C + + has no such Thing (threading model). (PS: I ignored the system-provided TLS ... )
Say so much; just want to say: For TLS, for performance! Of course, the unified threading model has a greater benefit: a unified and concise multithreaded interface.
Second, the task model
Like Java, the threading model itself derives from the task model (not my original version); This has the benefit of using the instantiated thread as a task (i.e., not executing the task through the thread that it holds). In some cases, there will be such a demand.
As the most fundamental interface, it needs to be simple enough:
class ITask: public interface{ public : virtual void run () = 0 ; public : virtual void interrupted () {} public : virtual tick_t getwaitingtime () const Span style= "COLOR: #000000" >{ return 0; }};
The most important and straightforward is the run () interface function, which is the task we are going to perform (so needless to say). It is worth mentioning that: interrupted () is a callback function that notifies the task that it was accidentally interrupted during execution (such as throwing an exception). As for Getwaitingtime () is prepared for the thread pool, if your thread pools support deferred execution.
Three, threading model
First, be aware of two points: what is a thread? What is it used to do??
In object-oriented, a thread (class) is able to open another thread (a relative process), and its purpose is nothing more than to execute code. So, it contains two sets of logic: A new thread is opened, and a task interface is executed. So, here are the following:
class Thread: public itask{protected: void execute ();};
It only needs to provide an interface for opening new threads relative to ITask: Execute. Call this function and let the new thread start executing the task defined by run.
Of course, it's far more than that; we can provide more control interfaces: Suspend, resume, interrupt (for thread break), and query interface: isstarted, ThreadID. However, there is an interface that can never be forgotten:
class Thread: public itask{protected: void execute (); Public : void Wait (); // here~};
Once the thread starts executing, its topmost (the child of the thread) must wait until the thread stops running before it can begin the destructor!! and the provision for such a wait is: wait. (There is a GC language that does not have this problem)
Four, thread local storage
TLS, where is it?? Yes, we still don't see the slightest figure. In fact, just behind execute-when it opens a new thread, it registers the new thread to create a new thread environment (TLS), and again, when the thread stops, it cancels the registration and deletes the environment.
At this point, we need a global thread runtime environment to manage the threads and store the appropriate TLS (or save its index).
Of course, there is a question worth proposing: where is TLS placed? is the global runtime environment, or the thread itself? (The operating system, typically through the thread's own call stack, to store TLS)
If, we really have a unified threading model, both can be chosen. Unfortunately, we could not have! The main thread cannot be constrained by any of our models (the main thread exists before the first line of code in the entire program executes). Of course, we can avoid this problem by completely not using the main thread (that is, any of our logic is executed in the non-main thread), and requires considerable caution, such as static initialization.
So, the only option is to put it in the Global runtime environment. At this point, what we see is probably this:
void Thread::execute () { getserviceas<ThreadService> ()login ();
...}
Everything is stored in the Threadservice; then, how to get TLS is also used naturally:
... Getserviceas<ThreadService> ()->getlocalas<xxtype>() .....
One thing to note is that we do not display the thread ID to index it, but inside the interface, we get the current thread ID through the system api:getcurrentthreadid.
V. Other
A lot of details, I did not mention, such as: Interrupted (), how to use?
Yes, there is no "detail" in all my articles, there are two reasons: not dozens of lines of code can be understood, my library is not open source. But, accordingly, all the design process and details have been presented to you, as long as you are not stupid, and have some interest and patience, it is not difficult to achieve (even better than what I said).
Well, this time, the content is small enough, probably, "tired", wrote some, and did not have any kind of people, to carry out the expected exchange (mainly look forward to different views); So, the probability that I'm going to write will probably also be getting lower ...
So far.
Talk about memory management technology (III), threading model