派生:线程在进程内派生出来,它即可由进程派生,也可由线程派生。
阻塞(Block) :如果一个线程在执行过程中需要等待某个事件发生,则被阻塞。
激活(unblock) :如果 阻塞 线程的事件发生,则该线程被激活并进入就绪队列。
调度(schedule) :选择一个就绪线程进入执行状态。
结束(Finish) :如果一个线程执行结束,它的寄存器上下文以及堆栈内容等将被释放。
线程的另一个执行特性是同步。线程中所使用的同步控制机制与进程中所使用的同步控制机制相同。
(1)创建线程
当创建一个新的进程时,也创建一个新的线程,进程中的线程可以在同一进程中创建新的线程中创建新的线程。
(2)终止线程
可以正常终止自己,也可能某个线程执行错误,由其它线程强行终止。终止线程操作主要负责释放线程占有的寄存器和栈。
(3)阻塞线程
当线程等待每个事件无法运行时,停止其运行。
(4)唤醒线程
当阻塞线程的事件发生时,将被阻塞的线程状态置为就绪态,将其挂到就绪队列。进程仍然具有与执行相关的状态。例如,所谓进程处于“执行”状态,实际上是指该进程中的某线程正在执行。对进程施加的与进程状态有关的操作,也对其线程起作用。例如,把某个进程挂起时,该进程中的所有线程也都被挂起,激活也是同样。
线程有两个基本类型
用户级线程
管理过程全部由用户程序完成,操作系统内核心只对进程进行管理。
系统级线程
系统级线程也是核心级线程,由操作系统内核进行管理。操作系统内核给应用程序提供相应的系统调用和应用程序接口API,以使用户程序可以创建、执行、撤消线程。
1.Unix International线程
SUN Solaris操作系统使用的线程叫做Unix International线程,支持内核线程、轻权进程和用户线程。一个进程可有大量用户线程;大量用户线程复用少量的轻权进程,轻权进程与内核线程一一对应。
用户级线程在调用核心服务时(如文件读写),需要“捆绑(bound)”在一个lwp上。永久捆绑(一个LWP固定被一个用户级线程占用,该LWP移到LWP池之外)和临时捆绑(从LWP池中临时分配一个未被占用的LWP)。
在调用系统服务时,如果所有LWP已被其他用户级线程所占用(捆绑),则该线程阻塞直到有可用的LWP。
如果LWP执行系统线程时阻塞(如read()调用),则当前捆绑在LWP上的用户级线程也阻塞。
Unix International线程的有关API
UNIX International 线程的头文件是<thread.h>。
1.创建用户级线程
int thr_create ( void * stack_base, size_t stack_size, void *(*start_routine)(void *), void * arg, long flags, thread_t * new_thr);
其中flags包括:THR_BOUND(永久捆绑), THR_NEW_LWP(创建新LWP放入LWP池),若两者同时指定则创建两个新LWP,一个永久捆绑而另一个放入LWP池。
2.等待用户级线程
int thr_join (thread_t wait_for, thread_t *dead, void **status);
3.挂起用户级线程
int thr_suspend (thread_t thr);
4.继续用户级线程
int thr_continue (thread_t thr);
5.退出用户级线程
void thr_exit (void *status);
6.返回当前用户级线程的线程标识符
thread_t thr_self ( void );
Pthreads(POSIX Thread)的相关API
Pthreads 线程的头文件是<pthread.h>。
1.创建用户级线程
int pthread_create(pthread_t * thread, const pthread_attr_t * attr, void *(*start_routine) (void *), void *arg);
2.等待用户级线程
int pthread_join(pthread_t thread, void ** retval);
3.退出用户级线程
void pthread_exit(void *retval);
4.返回当前用户级线程的线程标识符
pthread_t pthread_self(void);
5.用户级线程的取消
int pthread_cancel(pthread_t thread);
3.C++11线程
C++ 11 线程的头文件是<thread>。
1.创建用户级线程
std::thread::thread(Function&& f, Args&&... args);
2.等待用户级线程结束
std::thread::join();
3.脱离用户级线程控制
std::thread::detach();
4.交换用户级线程
std::thread::swap( thread& other );
4. C11线程
C11线程的头文件是<threads.h>。
C11线程仅仅是个“建议标准”,也就是说100%遵守C11标准的C编译器是可以不支持C11线程的。根据C11标准的规定,只要编译器预定义了__STDC_NO_THREADS__宏,就可以没有<threads.h>头文件,自然也就也没有下列函数。
1.创建用户级线程
int thrd_create( thrd_t *thr, thrd_start_t func, void *arg );
2.结束本线程
_Noreturn void thrd_exit( int res );
3.等待用户级线程运行完毕
int thrd_join( thrd_t thr, int *res );
4.返回当前线程的线程标识符
thrd_t thrd_current();
5. Win32线程
Win32线程的上下文包括:寄存器、核心栈、线程环境块和用户栈。
Win32线程状态
(1) 就绪状态:进程已获得除处理机外的所需资源,等待执行。(2) 备用状态:特定处理器的执行对象,系统中每个处理器上只能有一个处于备用状态的线程。
(3) 运行状态:完成描述表切换,线程进入运行状态,直到内核抢先、时间片用完、线程终止或进行等待状态。
(4) 等待状态:线程等待对象句柄,以同步它的执行。等待结束时,根据优先级进入运行、就绪状态。
(5) 转换状态:线程在准备执行而其内核堆栈处于外存时,线程进入 转换状态;当其内核堆栈调回内存,线程进入就绪状态。
(6) 终止状态:线程执行完就进入终止状态;如执行体有一指向线程对象的指针,可将线程对象重新初始化,并再次使用。
Win32线程的有关API
Win32线程的头文件是<Windows.h>,仅适用于Windows操作系统。
1.创建用户级线程
HANDLE WINAPI CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);
2.结束本线程
VOID WINAPI ExitThread(DWORD dwExitCode);
3.挂起指定的线程
DWORD WINAPI SuspendThread( HANDLE hThread );
4.恢复指定线程运行
DWORD WINAPI ResumeThread(HANDLE hThread);
5.等待线程运行完毕
DWORD WINAPI WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
6.返回当前线程的线程标识符
DWORD WINAPI GetCurrentThreadId(void);
7.返回当前线程的线程句柄
HANDLE WINAPI GetCurrentThread(void);
6. Java线程
1)最简单的情况是,Thread/Runnable的run()方法运行完毕,自行终止。
2)对于更复杂的情况,比如有循环,则可以增加终止标记变量和任务终止的检查点。
3)最常见的情况,也是为了解决阻塞不能执行检查点的问题,用中断来结束线程,但中断只是请求,并不能完全保证线程被终止,需要执行线程协同处理。[6]
4)IO阻塞和等锁情况下需要通过特殊方式进行处理。
5)使用Future类的cancel()方法调用。
6)调用线程池执行器的shutdown()和shutdownNow()方法。
7)守护线程会在非守护线程都结束时自动终止。
8)Thread的stop()方法,但已不推荐使用。
守护线程是特殊的线程,一般用于在后台为其他线程提供服务.
Java中,isDaemon():判断一个线程是否为守护线程.
Java中,setDaemon():设置一个线程为守护线程.
C# 守护线程
/**
* 本线程设置了一个超时时间
* 该线程开始运行后,经过指定超时时间,
* 该线程会抛出一个未检查异常通知调用该线程的程序超时
* 在超时结束前可以调用该类的cancel方法取消计时
* @author solonote
*/
public class TimeoutThread extends Thread{
/**
* 计时器超时时间
*/
private long timeout;
/**
* 计时是否被取消
*/
private boolean isCanceled = false;
/**
* 当计时器超时时抛出的异常
*/
private TimeoutException timeoutException;
/**
* 构造器
* @param timeout 指定超时的时间
*/
public TimeoutThread(long timeout,TimeoutException timeoutErr) {
super();
this.timeout = timeout;
this.timeoutException = timeoutErr;
//设置本线程为守护线程
this.setDaemon(true);
}
/**
* 取消计时
*/
public synchronized void cancel()
{
isCanceled = true;
}
/**
* 启动超时计时器
*/
public void run()
{
try {
Thread.sleep(timeout);
if(!isCanceled)
throw timeoutException;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}