线程的基本知识和使用方法

本文介绍了线程的基本操作,包括创建、终止、阻塞和唤醒,并详细讲解了Unix International线程、POSIX线程、C++11线程、C11线程和Win32线程的API用法,以及线程的状态变化和分类。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程 - 基本操作

派生:线程在进程内派生出来,它即可由进程派生,也可由线程派生。

线程的状态与操作 线程的状态与操作图册

阻塞(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 );


2.POSIX线程

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) 就绪状态:进程已获得除处理机外的所需资源,等待执行。
线程 Windows NT的线程状态图册

 (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线程

java线程示意 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();
}
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值