Thread State
During the lifetime of a thread , it is possible to convert between multiple states. Different operating systems can implement different threading models, defining many different thread states, each of which
The
State can also contain multiple child states. In general, however, the following States are common:
ready: Participate in scheduling, waiting to be executed. Once selected, start execution immediately.
run: CPU occupied, running.
Hibernate: Temporarily does not participate in scheduling, waiting for a specific event to occur.
Abort: finished running, waiting to recycle threads Resources (Note that this is easily misunderstood, explained later).
Thread environment
thread exists in the process. All global resources within a process are visible to each internal thread .
There are several typical global resources within a process:
code area. This means that all the visible function code in the current process space is visible to each thread .
static Storage area. Global variables. static variables.
Dynamic Storage area. That is, heap space. Typical local resources in
threads are:
local stack space. The function call stack that holds the thread , local variables inside the function, and so on.
Partial Register variables. For example, this thread Next executes a pointer offset to the code.
Once a process is initiated, a default thread is generated first, usually called the thread as the primary thread . A thread that is entered through the main function in a C + + program
。 threads derived from the main thread are called from the thread, and the thread can have its own entry function, which acts as the main function of the master thread .
This function is specified by the user. Both Pthread and WINAPI are implemented by passing in function pointers. When you specify a thread entry function, you can also specify parameters for the entry function.
Just as the main function has a fixed format requirement, the thread 's entry function generally has a fixed format requirement, and the parameters are usually void * types, and the return type is
Pthread is void *, WINAPI is unsigned int, and it needs to be a global function.
The most common threading model, in addition to the main thread is special, once the other threads are created, the other is peer to peer, there is no implied
Hierarchical relationships. The maximum number of threads that each process can create is determined by the specific implementation.
In order to better understand the above concepts, the following specific code to explain in detail.
Thread class interface Definition
a thread class whatever task you perform, the basic commonality is
Create and start thread
Stop thread
There's also the ability to sleep, to wait, Can separate execution (a bit of a mouthful, explained later).
There are others that can continue to add ...
The concept of thread is abstracted, and you can define the following classes for it:
file thread.h
#ifndef __thread__h_
#define __ Thread__h_
Class Thread
{
Public:
Thread ();
Virtual ~thread ();
int start (void * = NULL);
void Stop ();
void sleep (int);
void Detach ();
void * Wait ();
Protected:
virtual void * Run (void *) = 0;
Private:
//This part of Win and Unix slightly different, first not defined, followed by separate implementation.
//By the way, I am not used to writing Chinese comments, here to better understand a
//point or choose Chinese.
...
};
#endif
The Thread::start () function is a thread -start function whose input parameter is an untyped pointer.
The Thread::stop () function aborts the current thread .
The Thread::sleep () function lets the current thread hibernate for a given time in seconds.
The Thread::run () function is a thread function call that implements a thread class.
Thread:: The concepts involved in thedetach() and thread::wait () functions are slightly more complex. Explain later.
The thread class is a virtual base class, and derived classes can overload their own thread functions. Here is an example.
Sample Program
Code written is not exquisite, violent type conversion more, welcome to have leisure class beautification, thanked the first.
File create.h
#ifndef __creator__h_
#define __creator__h_
#include <stdio.h>
#include "Thread.h"
Class Create:public Thread
{
Protected
void * Run (void * param)
{
char * msg = (char*) param;
printf ("%s\n", msg);
Sleep (100); Try canceling this line of comments to see how the results are different.
printf ("One day past.\n");
return NULL;
}
};
#endif
Then, implement a main function to see the specific effect:
File Genesis.cpp
#include <stdio.h>
#include "create.h"
int main (int argc, char** argv)
{
Create Monday;
Create Tuesday;
printf ("At the first God made the heaven and the earth.\n");
Monday.start ("Naming, day, and the dark, night, the first day.");
Tuesday.start ("gave the arch the name of Heaven, the second day.");
printf ("These is the generations of the heaven and the earth.\n");
return 0;
}
Compile and run, the program output is as follows:
At the first God made the heaven and the earth.
These is the generations of the heaven and the earth.
Surprisingly, the child threads created by the Monday and Tuesday objects do not appear to be executing! What is this for? Don't worry, add the following statement before the last printf statement
:
Monday.wait ();
Tuesday.wait ();
To recompile the run, the new output is as follows:
At the first God made the heaven and the earth.
Naming the light, day, and the dark, night, the first day.
One day past.
Gave the arch the name of Heaven, the second day.
One day past.
These is the generations of the heaven and the earth.
To illustrate this problem, you need to understand the meaning of the thread::detach() and thread::wait () two functions that are not explained earlier.
In both Windows and POSIX, the default relationship between the master thread and the child thread is:
The execution of all child threads terminates, regardless of whether the child thread executes or not, once the master thread has finished executing the exit. This is the end of the entire process or zombie (some threads maintain a
A state that terminates execution but has not yet been destroyed, and the process must be destroyed after all its threads have been destroyed, the process is in a zombie state, and in the output of the first example, you can see
Until the child thread has finished executing, the main () function of the master thread has been executed, and all child threads are terminated.
It is important to emphasize that the thread function exits, or terminates in other extraordinary ways, and the thread enters the terminating state (please review the thread state described above), but be sure to remember
, the system resources assigned to the thread are not necessarily released after entering the terminating state, and may not be released until the system restarts. Terminating state of the thread ,
Still exists as a thread entity in the operating system. (This is consistent between win and UNIX.) And when the thread is destroyed depends on the thread properties.
Typically, this termination is not the result we expect, and a potential problem is a child thread that terminates without execution, except that it consumes system resources as a thread entity
, the resources owned by its thread functions (dynamic memory requested, open files, open network ports, etc.) may not be released. So, in response to this problem,
Two relationships are typically defined between a master thread and a child thread :
can meet (joinable). In this relationship, the master thread needs to explicitly perform the wait operation. After the child thread finishes, the wait operation for the master thread finishes, and the child thread
Rendezvous with the main thread . The main thread then resumes the next operation after the wait operation. The master thread must rendezvous with a sub- thread that can be joined, and in the thread class, this operation passes
The wait () function implementation of the child thread object is called inside the thread function of the main thread . This is the reason why the above plus three wait () calls are displayed correctly. Must emphasize the
Is that even if the child thread is able to execute before the main thread , entering the terminating state, it must also show the rendezvous operation, otherwise the system will never actively destroy the thread , assigning
system resources ( thread ID or handle, thread management-related system resources) that are given to the thread will never be released.
Phase separation (detached). As the name implies, this means that the child thread does not need to rendezvous with the main thread , which is a separate phase. In this case, once the child thread enters the terminating state
, the system immediately destroys the thread and reclaims the resource. You do not need to call wait () to rendezvous within the main thread . In the thread class, call Detach() to bring the thread into the detached state.
This approach is often used in situations where the number of threads is high, sometimes allowing the master thread to wait for the child thread to end one by one, or to have the master thread Schedule the wait order for each child thread to end. It's very sleepy.
Difficult or impossible. So in the case of more concurrent child threads , this approach is often used.
By default, threads are created to be joined. A thread that can be joined can become a separate thread by calling the Detach() method. But the reverse is not.
UNIX implementations
File Thread.h
#ifndef __thread__h_
#define __thread__h_
Class Thread
{
Public
Thread ();
Virtual ~thread ();
int start (void * = NULL);
void Stop ();
void sleep (int);
void detach();
void * Wait ();
Protected
virtual void * Run (void *) = 0;
Private
pthread_t handle;
BOOL started;
BOOL detached;
void * THREADFUNCPARAM;
friend void * ThreadFunc (void *);
};
The thread function in Pthread must be a global function in order to solve this problem
Declare it as static to prevent code outside this file from calling this function directly.
The implementation here uses a method called virtual friend function idiom.
Static void * ThreadFunc (void *);
#endif
File Thread.cpp
#include <pthread.h>
#include <sys/time.h>
#include "Thread.h"
static void * ThreadFunc (void * threadobject)
{
Thread * thread = (thread *) Threadobject;
Return Thread->run (Thread->threadfuncparam);
}
Thread::thread ()
{
started = detached = false;
}
Thread::~thread ()
{
Stop ();
}
BOOL Thread::start (void * param)
{
pthread_attr_t attributes;
Pthread_attr_init (&attributes);
if (detached)
{
Pthread_attr_setdetachstate (&attributes, pthread_create_detached);
}
Threadfuncparam = param;
if (Pthread_create (&handle, &attributes, ThreadFunc, this) = = 0)
{
started = true;
}
Pthread_attr_destroy (&attribute);
}
void Thread::detach()
{
If (started &&!detached)
{
Pthread_detach (handle);
}
detached = true;
}
void * THREAD::WAIT ()
{
void * status = NULL;
If (started &&!detached)
{
Pthread_join (handle, &status);
}
return status;
}
void Thread::stop ()
{
If (started &&!detached)
{
Pthread_cancel (handle);
Pthread_detach (handle);
detached = true;
}
}
void thread::sleep (unsigned int milliSeconds)
{
Timeval Timeout = {milliseconds/1000, millisecond%1000};
Select (0, NULL, NULL, NULL, &timeout);
}
Windows implementation
File Thread.h
#ifndef _thread_specifical_h__
#define _thread_specifical_h__
#include <windows.h>
static unsigned int __stdcall threadfunction (void *);
Class Thread {
Friend unsigned int __stdcall threadfunction (void *);
Public
Thread ();
Virtual ~thread ();
int start (void * = NULL);
void * Wait ();
void Stop ();
void detach();
static void sleep (unsigned int);
Protected
virtual void * Run (void *) = 0;
Private
HANDLE Threadhandle;
BOOL started;
BOOL detached;
void * PARAM;
unsigned int threadID;
};
#endif
File Thread.cpp
#include "stdafx.h"
#include <process.h>
#include "Thread.h"
unsigned int __stdcall threadfunction (void * object)
{
Thread * thread = (thread *) object;
return (unsigned int) thread->run (thread->param);
}
Thread::thread ()
{
started = false;
detached = false;
}
Thread::~thread ()
{
Stop ();
}
int Thread::start (void* pra)
{
if (!started)
{
param = PRA;
if (Threadhandle = (HANDLE) _beginthreadex (NULL, 0, threadfunction, this, 0, &threadid))
{
if (detached)
{
CloseHandle (Threadhandle);
}
started = true;
}
}
return started;
}
Wait for the current thread to end.
void * THREAD::WAIT ()
{
DWORD status = (DWORD) NULL;
If (started &&!detached)
{
WaitForSingleObject (Threadhandle, INFINITE);
GetExitCodeThread (Threadhandle, &status);
CloseHandle (Threadhandle);
detached = true;
}
return (void *) status;
}
void Thread::detach()
{
If (started &&!detached)
{
CloseHandle (Threadhandle);
}
detached = true;
}
void Thread::stop ()
{
If (started &&!detached)
{
TerminateThread (threadhandle, 0);
Closing A thread handle does not terminate
The associated thread.
To remove a thread object, you must terminate the thread,
Then close all handles to the thread.
The thread object remains in the system until
The thread has terminated and all handles to it having been
Closed through a call to CloseHandle
CloseHandle (Threadhandle);
detached = true;
}
}
void thread::sleep (unsigned int delay)
{
:: Sleep (delay);
}
Summary
The main purpose of this section is to help the novice to establish a basic threading concept, based on which a generic threading class with a minimal interface is abstracted. In the sample program section, Beginners
The difference between parallel and serial program execution can be realized. If you are interested, you can make further expansion and try on the basis of the existing thread class. If you think the line
The concept of the process needs to be further refined, we can further expand and refine the existing thread class.
To get a better idea, one suggestion is to look at other languages, the thread libraries of other platforms, which concepts are abstracted by thread classes. such as Java, Perl and other cross-
How the platform language is defined, how Microsoft supports multi- threading from WINAPI to dotnet, and how its threading classes are defined. This helps to better understand the thread
Model and the underlying concepts.
In addition, we encourage you to write more code, and then try to write some code, it will also help to better understand the characteristics of multi- threaded programs. For example, the line that starts first
The process does not necessarily end first. The execution of the thread may alternately occur. Replacing printf with cout may have new discoveries, and so on.
Once each child thread is created, it is given its own life. Poor management, a special case of a lone pig is very annoying.
For starters, writing multithreaded programs can be a lot of confusing bugs. Often not to consider efficiency, avoid deadlocks and other stages of problems, and
and difficult to understand and debug. This is very normal, please do not be discouraged, follow-up article will try to explain the causes of various common problems, to guide you to avoid common mistakes. can now
The problems that you often encounter in the entry phase are:
Memory leaks, system resource leaks.
The execution of the program is confusing, but the result is correct after inserting the sleep statement at some point.
The program crash, but after removing or adding some unrelated statements, the entire program runs normally (false).
Multi- threaded program execution results are completely illogical, as expected.
At this point, if you do a change, try some examples, the multi- threaded program should have some perceptual knowledge. At first, as long as the basic concepts are understood, the back can be
To build a very complex class in step-by-step. But at first do not too much, or will make haste, the more confused.
Threads (the role of detach)