赞
踩
此专栏为移动机器人知识体系下的编程语言中的 C {\rm C} C++从入门到深入的专栏,参考书籍:《深入浅出 C {\rm C} C++》(马晓锐)和《从 C {\rm C} C到 C {\rm C} C++精通面向对象编程》(曾凡锋等)。
进程是操作系统资源分配和调用的基本单位,其独立享有系统分配的资源;线程是从属于进程的一个独立执行单位,可以与其从属进程的其他线程共享资源,线程是 C P U {\rm CPU} CPU调度的基本单位;
当一个进程被建立后,其包含进程控制块、程序块、数据段和其他资源,进程占用系统一定的资源,这些资源在进程启动时创建,在进程终止时被系统回收;
线程是进程中的一个相对独立的执行单位,它能独立地处理某个任务,线程由进程创建,并受到进程的管制;
一个进程可以创建多个线程,但至少有一个线程,当一个进程启动后,首先生成一个默认的线程,这个线程称为主线程;
多线程可以让一个应用程序同时处理几个任务,如:一个通信程序,可以建立两个线程,一个负责接收并处理数据,一个负责发送数据,相互独立,互不影响;
一个进程可以包含多个线程,这些线程享有进程的系统资源,包括 C P U {\rm CPU} CPU资源;当一个进程中包含多个线程时,由操作系统为每个线程分配 C P U {\rm CPU} CPU执行时间片,在某一个时刻只能执行一个线程的代码,多个线程在 C P U {\rm CPU} CPU中轮流执行,这些执行线程的 C P U {\rm CPU} CPU时间片和线程切换时间非常短,宏观上几乎可以忽略不计;
线程的优先级是操作系统为线程分配 C P U {\rm CPU} CPU时间片的依据,优先级高的线程会优先得到 C P U {\rm CPU} CPU的执行时间片,优先级越高,在同一个时间片竞争中获得 C P U {\rm CPU} CPU资源的概率越大;
线程从创建到消亡,存在于不同的状态,如下图所示:
用一个初始函数创建线程,用初始函数创建线程时,直接用函数名进行类对象的实例化,语法格式如下:
return_type function_name(parameter list)
{
函数体;
}
初始函数创建线程实例,使用 t h r e a d {\rm thread} thread库创建一个线程 ( e x a m p l e 15 _ 1. c p p ) ({\rm example15\_1.cpp}) (example15_1.cpp):
/**
* 作者:罗思维
* 时间:2024/04/05
* 描述:使用thread库建立一个线程。
*/
#include <iostream>
#include <thread>
using namespace std;
// 线程函数;
void print_thread() {
cout << "线程1执行." << endl;
cout << "线程2执行." << endl;
cout << "线程3执行." << endl;
}
int main() {
// 创建线程对象,用线程函数实例化;
thread my_thread(print_thread);
// 阻塞主线程;
my_thread.join();
cout << "主线程执行." << endl;
return 0;
}
用类对象创建一个线程,用类对象创建线程时,用对象名对线程对象实例化,实例如下 ( e x a m p l e 15 _ 2. c p p ) ({\rm example15\_2.cpp}) (example15_2.cpp):
/**
* 作者:罗思维
* 时间:2024/04/05
* 描述:用类对象创建一个线程。
*/
#include <iostream>
#include <thread>
using namespace std;
class TT {
public:
int it;
// 构造函数;
TT(int m_it): it(m_it) {
cout << "构造函数被执行." << endl;
}
// 复制构造函数;
TT(const TT& t): it(t.it) {
cout << "复制构造函数被执行." << endl;
}
// 析构函数;
~TT() {
cout << "析构函数被执行." << endl;
}
// 重载运算符();
void operator()() {
cout << "it的值:" << it << endl;
}
};
int main() {
int it = 6;
TT tt(it); // 调用构造函数;
thread my_thread(tt); // 创建线程对象并用类对象实例;
my_thread.join(); // 阻塞主线程main函数;
cout << "主线程执行." << endl;
return 0;
}
用 l a m b d a {\rm lambda} lambda表达式创建一个线程,实例如下 ( e x a m p l e 15 _ 3. c p p ) ({\rm example15\_3.cpp}) (example15_3.cpp):
/**
* 作者:罗思维
* 时间:2024/04/05
* 描述:用lambda表达式创建一个线程。
*/
#include <iostream>
#include <thread>
using namespace std;
int main() {
// 用lambda表达式创建一个线程;
auto my_lam_thread = [] {
cout << "线程开始执行." << endl;
cout << "线程执行结束." << endl;
};
// 创建线程对象并用lambda表达式实例化;
thread my_thread(my_lam_thread);
my_thread.join();
cout << "主线程执行结束." << endl;
return 0;
}
用 C r e a t e T h r e a d ( ) {\rm CreateThread()} CreateThread()函数创建线程,实例如下 ( e x a m p l e 15 _ 4. c p p ) ({\rm example15\_4.cpp}) (example15_4.cpp):
// CreateThread()函数原型:
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, // 指向安全属性的指针
SIZE_T dwStackSize, // 初始化栈的大小
LPTHREAD_START_ROUTINE lpStartAddress, // 线程函数指针
LPVOID lpParameter, // 传递给线程函数的参数
DWORD dwCreationFlags, // 创建标志
LPDWORD lpThreadId // 用于存储新线程ID的变量
);
// 参数说明:
// lpThreadAttributes:指向_SECURITY_ATTRIBUTES结构体的指针,一般设置为NULL;
// dwStackSize:设定线程堆栈的大小,一般设置为0,系统自动进行调整其大小;
// lpStartAddress:指向线程函数的指针,调用时将线程函数的地址传入,传入函数名即可;
// lpParameter:指向线程函数的结构体指针,如果没有参数,设置为NULL,若有,则将参数列表定义成一个结构体传入;
// dwCreationFlags:线程建立时的状态标志,可设为0、CREATE_SUSPENDED、THREAD_TERMINATE等,
// 当设置为0时,创建线程后立即被激活;当设置为CREATE_SUSPENDED时,线程创建后立即被挂起;
// lpThreadId:返回创建的这个线程的句柄,创建失败返回false;
/**
* 作者:罗思维
* 时间:2024/04/05
* 描述:使用CreateThread创建两个线程。
*/
#include <iostream>
#include <Windows.h>
#include <thread>
using namespace std;
// 定义结构体存储传入线程函数的参数;
typedef struct _param {
long lVal1;
char cVal2;
} PARAM, * PPARAM;
// 定义线程函数;
DWORD WINAPI ThreadProc(LPVOID lpParam) {
PPARAM pParam;
pParam = (PPARAM)lpParam;
return 0;
}
int main() {
HANDLE hThread[2];
DWORD dwThreadId[2];
PPARAM pParam = new PARAM;
pParam->lVal1 = 1000;
pParam->cVal2 = 'W';
hThread[0] = CreateThread(
NULL, // 安全属性;
0, // 线程栈大小;
ThreadProc, // 线程函数地址;
pParam, // 传递参数;
0, // 状态标志;
&dwThreadId[0] // 线程标识ID;
);
pParam->lVal1 = 2000;
pParam->cVal2 = 'E';
hThread[1] = CreateThread(
NULL,
0,
ThreadProc,
pParam,
0,
&dwThreadId[1]
);
// 等待线程完成返回;
WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
// 关闭线程;
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
return 0;
}
// 1.设定线程优先级的API函数:
BOOL WINAPI SetThreadPriority(
HANDLE hThread,
int nPriority
);
// 2.获取线程优先级的API函数:
Int WINAPI GetThreadPriority(
HANDLE hThread
);
// 1.线程挂起函数SuspendThread(),函数原型如下:
// SuspendThread()函数用来挂起线程,即暂停线程的执行;
DWORD WINAPI
SuspendThread(
HANDLE hThread
);
// 2.线程恢复函数ResumeThread(),函数原型如下:
// ResumeThread()函数用来恢复已经挂起的线程使其重新开始运行;
DWORD WINAPI
ResumeThread(
HANDLE hThread
);
线程挂起和恢复实例 ( e x a m p l e 15 _ 5. c p p ) ({\rm example15\_5.cpp}) (example15_5.cpp):
/**
* 作者:罗思维
* 时间:2024/04/05
* 描述:线程的挂起和恢复。
*/
#include <iostream>
#include <thread>
#include <Windows.h>
using namespace std;
DWORD WINAPI ThreadProc(LPVOID lpParam) {
int pParam;
pParam = *(int*)(lpParam);
while (true) {
printf("Thread %d \n", pParam);
Sleep(1000);
}
return 0;
}
int main() {
HANDLE hThread[2];
DWORD dwThreadId[2];
int nParam[2] = {1, 2};
hThread[0] = CreateThread(
NULL,
0,
ThreadProc,
&nParam[0],
0,
&dwThreadId[0]
);
Sleep(100);
hThread[1] = CreateThread(
NULL,
0,
ThreadProc,
&nParam[1],
0,
&dwThreadId[1]
);
Sleep(2000);
SuspendThread(hThread[0]); // 挂起;
cout << "Thread 1 Suspend." << endl;
Sleep(2000);
ResumeThread(hThread[0]); // 恢复;
cout << "Thread 1 Resume." << endl;
Sleep(2000);
TerminateThread(hThread[0], 0); // 强制终止线程;
TerminateThread(hThread[1], 0);
WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
return 0;
}
// 运行结果:
Thread 1
Thread 2
Thread 1
Thread 2
Thread 1
Thread 1 Suspend.
Thread 2
Thread 2
Thread 1 Resume.
Thread 2
Thread 1
Thread 2
Thread 1
调用 T e r m i n a t e T h r e a d ( ) {\rm TerminateThread()} TerminateThread()函数结束线程,其原型为:
BOOL WINAPI
TerminateThread(
HANDLE hThread,
DWORD dwExitCode
);
// 参数说明:
// dwExitCode:设定线程的退出码;
// TerminateThread()函数在终止线程时,不释放线程占用的资源,大部分情况下它是不安全的;
// 如果使用此函数,需要再调用CloseHandle()函数释放线程的堆栈资源;
使用 E x i t T h r e a d ( ) {\rm ExitThread()} ExitThread()函数结束线程,函数原型为:
VOID WINAPI
ExitThread(
DWORD dwExitCode
);
// ExitThread()函数用于线程自我终止的情况,主要在线程内被调用;
使用全局变量结束线程,改变全局变量使线程的执行函数返回,则该线程终止;
项目需求:在一个程序中开辟两个线程:一个线程用于计算并显示奇数,另一个线程用于计算并显示偶数,当计算数字超过 10 10 10时,各自退出线程。
代码实现 ( e x a m p l e 15 _ 6. c p p ) ({\rm example15\_6.cpp}) (example15_6.cpp):
/**
* 作者:罗思维
* 时间:2024/04/05
* 描述:一个线程用于计算并显示奇数,一个线程用于计算并显示偶数。
*/
#include <iostream>
#include <string>
#include <process.h>
#include <windows.h>
#include <thread>
#define THREADS_NUM 2
using namespace std;
void __cdecl thread1(void *params);
void __cdecl thread2(void *params);
int main() {
HANDLE hThreads[THREADS_NUM];
hThreads[0] = (HANDLE)_beginthread(thread1, 0, NULL);
hThreads[1] = (HANDLE)_beginthread(thread2, 0, NULL);
Sleep(1000);
CloseHandle(hThreads[0]);
CloseHandle(hThreads[1]);
return 0;
}
void __cdecl thread1(void *params) {
int n = 0;
while (n <= 10) {
if (n / 2 == 0) {
printf("Thread1-%d\n", n);
//cout << "Thread1-" << n << endl;
}
n++;
Sleep(2);
}
printf("Thread1 exit.\n");
return;
}
void __cdecl thread2(void *params) {
int n = 0;
while (n <= 10) {
if (n / 2 != 0) {
printf("Thread2-%d\n", n);
//cout << "Thread1-" << n << endl;
}
n++;
Sleep(2);
}
printf("Thread2 exit.\n");
return;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。