线程的基本概念
基本概念:线程,即轻量级进程(LWP:LightWeight Process),是程序执行流的最小单元。一个标准的线程由线程ID、当前指令指针(PC),寄存器集合和堆栈组成。线程是进程中的一个实体,是被系统独立调度和分派的基本单位。线程不拥有系统资源,近拥有少量运行必须的资源。
线程的基本状态
基本状态:就绪、阻塞和运行三种基本状态。
就绪状态:指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;
运行状态:指线程占有处理机正在运行;
阻塞状态:指线程在等待一个事件(如信号量),逻辑上不可执行。
进程和线程的关系
简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
为什么使用多线程
- 避免阻塞 大家知道,单个进程只有一个主线程,当主线程阻塞的时候,整个进程也就阻塞 了,无法再去做其它的一些功能了。
- 避免 CPU 空转 应用程序经常会涉及到 RPC,数据库访问,磁盘 IO 等操作,这些操作的速度比 CPU 慢很多,而在等待这些响应时,CPU 却不能去处理新的请求,导致这种单线 程的应用程序性能很差。 cpu > 内存 > 磁盘
- 提升效率 一个进程要独立拥有 4GB 的虚拟地址空间,而多个线程可以共享同一地址空间, 线程的切换比进程的切换要快得多。
创建线程
CreateThread
需要添加<windows.h>
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,//SD
SIZE_T dwStackSize,//initialstacksize
LPTHREAD_START_ROUTINE lpStartAddress,//threadfunction
LPVOID lpParameter,//threadargument
DWORD dwCreationFlags,//creationoption
LPDWORD lpThreadId//threadidentifier
)
1.第一个参数 lpThreadAttributes 表示线程内核对象的安全属性,一般传入 NULL 表示使用默认设置。
2.第二个参数 dwStackSize 表示线程栈空间大小。传入 0 表示使用默认大小 (1MB)。
3.第三个参数 lpStartAddress 表示新线程所执行的线程函数地址,多个线程 可以使用同一个函数地址。
4.第四个参数 lpParameter 是传给线程函数的参数。
5.第五个参数 dwCreationFlags 指定额外的标志来控制线程的创建,为 0 表 示线程创建之后立即就可以进行调度,如果为 CREATE_SUSPENDED 则表 示线程创建后暂停运行,这样它就无法调度,直到调用 ResumeThread()。
6.第六个参数 lpThreadId 将返回线程的 ID 号,传入 NULL 表示不需要返回 该线程 ID 号
例子:
#include <iostream>
#include <windows.h>
DWORD WINAPI LaoWang(void* arg)
{
int count = *(int*)arg;
for (int i = 0; i < count; i++)
{
Sleep(4000);
puts("老王唱歌");
}
return 0;
}
DWORD WINAPI XiaoHong(void* arg)
{
int count = *(int*)arg;
for (int i = 0; i < count; i++)
{
Sleep(3000);
puts("小红俯卧撑");
}
return 0;
}
DWORD WINAPI XiaoMing(void* arg)
{
int count = *(int*)arg;
for (int i = 0; i < count; i++)
{
Sleep(2000);
puts("小明甩头发");
}
return 0;
}
int main()
{
HANDLE threadArry[3];
int laowang = 30, xiaohong = 30, xiaoming = 30;
threadArry[0] = CreateThread(NULL, 0, LaoWang, (void*)&laowang, 0, NULL);
threadArry[1] = CreateThread(NULL, 0, XiaoHong, (void*)&xiaohong, 0, NULL);
threadArry[2] = CreateThread(NULL, 0, XiaoMing, (void*)&xiaoming, 0, NULL);
WaitForMultipleObjects(3,threadArry,TRUE, INFINITE);
for (int i = 0; i < 3; i++)
{
CloseHandle(threadArry[i]);
}
}
_beginthreadex
需要添加<process.h>库
需要添加<<windows.h>库
unsigned long _beginthreadex(
void *security, // 安全属性, 为 NULL 时表示默认安全性
unsigned stack_size, // 线程的堆栈大小, 一般默认为 0
unsigned(_stdcall *start_address)(void *), // 线程函数
void *argilist, // 线程函数的参数
unsigned initflag, // 新线程的初始状态,0 表示立即执行,//CREATE_SUSPENDED 表示创建之后挂起
unsigned *threaddr // 用来接收线程 ID
);
//返回值 : // 成功返回新线程句柄, 失败返回 0
// __stdcall 表示 1.参数从右向左压入堆栈 2.函数被调用者修改堆栈
例子:
#include <iostream>
<