一、C++多线程第一次总结,这里仅仅总结了std::thread和CreateThread用法,后续文章会更新全面的用法。为了编写方便,所有的用法解释都写在代码注释里面了。废话不多说,直接上代码。
// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <thread>
#include <string>
#include <windows.h>
#include <mutex>
//声明全局互斥量对象做线程同步
std::mutex mutexx;
//声明全局临界区对象做线程同步
CRITICAL_SECTION cs;
//结构体
struct MyStruct
{
const std::string content;
const int id;
};
void show1(const char str[], const int id)
{
mutexx.lock();
std::cout << "测试函数1线程: " << id << ",Output " << str << std::endl;
Sleep(100);//必须包含#include <windows.h>才可以使用Sleep
mutexx.unlock();
}
void show2(const char str[])
{
EnterCriticalSection(&cs);
std::cout << "测试函数2线程: " << ",Output " << str << std::endl;
Sleep(500);
LeaveCriticalSection(&cs);
}
DWORD WINAPI show3(LPVOID lpargs)
{
EnterCriticalSection(&cs);
MyStruct *p = (MyStruct *)lpargs;//转换为结构体指针
std::cout << p->content << ",ID: " << p->id << std::endl;
Sleep(2000);
LeaveCriticalSection(&cs);
return 0;
}
//利用std::thread创建线程
void test1()
{
//这种创建线程的方式,当线程创建完成,就会立马执行线程函数。
//可以传递一个或者多个参数,std::thread t1(“函数名”, "函数参数1", “函数参数2”)
//t1.join(); //表示同步(阻塞),调用线程走完,才能走后面的流程
//t1.detach(); //表示异步(不会阻塞),主线程只触发此线程,后面和此线程无关
std::thread t1(show1, "hello cplusplus!", 1);
std::thread t2(show1, "你好,C++!", 2);
std::thread t3(show1, "hello!", 3);
t1.join(); t2.join(); t3.join();
//t1.detach(); t2.detach(); t3.detach();
std::cout << "测试函数1线程,一共三个线程全部执行完毕 " << std::endl;
//调用t1.join(); t2.join(); t3.join();后
//代码运行到这里,证明声明的三个线程已经全部运行完毕,后面代码可以综合三个线程的结果,执行后面的判断
}
//利用CreateThread创建线程
void test2()
{
//注释:
//这种创建线程的方式,当线程创建完成,可以选择立马执行或者先挂起后面再唤醒线程执行。
//CreateThread默认只能传递一个参数。如果需要多个参数,可以声明函数时,传入结构体。
//CreateThread的返回值是线程的句柄, 失败的话就返回NULL
//CreateThread函数原型
//HANDLE CreateThread(
// LPSECURITY_ATTRIBUTES lpThreadAttributes,
// DWORD dwStackSize,
// LPTHREAD_START_ROUTINE lpStartAddress,
// LPVOID lpParameter,
// DWORD dwCreationFlags,
// LPDWORD lpThreadID
//);
//第一个参数 lpThreadAttributes 表示线程内核对象的安全属性,一般传入NULL表示使用默认设置。
//第二个参数 dwStackSize 表示线程栈空间大小。传入0表示使用默认大小(1MB)。
//第三个参数 lpStartAddress 表示新线程所执行的线程函数地址,多个线程可以使用同一个函数地址。
//第四个参数 lpParameter 是传给线程函数的参数。
//第五个参数 dwCreationFlags 指定额外的标志来控制线程的创建,为0表示线程创建之后立即就可以进行调度,如果为CREATE_SUSPENDED则表示线程创建后暂停运行,这样它就无法调度,直到调用ResumeThread()。
//第六个参数 lpThreadId 将返回线程的ID号,传入NULL表示不需要返回该线程ID号。
//测试单个线程执行
HANDLE hThread;
DWORD threadId;
MyStruct struct1{
"单个线程执行传递多个参数的线程函数",1};
hThread = CreateThread(NULL, 0, show3, &struct1, 0, &threadId);
//注释:
// WaitForSingleObject("线程句柄",“等待时间(单位ms)”)
//WaitForSingleObject在等待时间内,线程执行完成,则返回0,否则返回值大于0
//等待时间如果设置为INFINITE,则会阻塞直到对应线程执行完成。等待时间如果设置为0,则不会阻塞直接运行后续代码。如果设置1000,则线程阻塞1000ms后,执行后续代码。
DWORD ret;
ret = WaitForSingleObject(hThread, 2500);
CloseHandle(hThread);
std::cout << "单个线程全部执行完毕。 " << "规定时间内线程运行完成与否:" << ret << std::endl;
//代码运行到这里,证明声明的三个线程已经全部运行完毕,后面代码可以综合三个线程的结果,执行后面的判断
//*******************************************************************************************************************************
//*******************************************************************************************************************************
//测试多线程并发
//注释:
//DWORD WaitForMultipleObjects(
// DWORD nCount, // number of handles in the handle array
// CONST HANDLE *lpHandles, // pointer to the object-handle array
// BOOL fWaitAll, // wait flag
// DWORD dwMilliseconds // time-out interval in milliseconds
//);
//参数解析:
// DWORD 就是 Double Word, 每个word为2个字节的长度,DWORD双字即为4个字节,每个字节是8位。
// nCount 指定列表中的线程句柄数量 最大值为MAXIMUM_WAIT_OBJECTS(64)
// *lpHandles 线程句柄数组的指针(数组)。lpHandles为指定对象句柄组合中的第一个元素 HANDLE类型可以为(Event,Mutex,Process,Thread,Semaphore)数组
// bWaitAll 等待的类型,如果为TRUE,表示除非所有对象都发出信号(所有都执行完成),否则就一直等待下去;如果FALSE,表示任何一个对象发出信号即可
// dwMilliseconds指定要等候的毫秒数。如设为零,表示立即返回。如指定常数INFINITE,则可根据实际情况无限等待下去
//WaitForMultipleObjects在等待时间内,线程执行完成,则返回0,否则返回值大于0
const int thNum = 5;
HANDLE hThread2[thNum];
DWORD threadId2[thNum];
for (int i = 0; i < thNum; i++)
{
MyStruct struct2{
"多线程并发执行传递多个参数的线程函数",i };
hThread2[i] = CreateThread(NULL, 0, show3, &struct2, 0, &threadId2[i]);
}
DWORD ret2;
ret2 = WaitForMultipleObjects(thNum, hThread2, true, 100);
for (int i = 0; i < thNum; i++)
{
CloseHandle(hThread2[i]);
}
std::cout << "多个线程并发全部执行完毕。 " << "规定时间内线程运行完成与否:" << ret2 << std::endl;
//代码运行到这里,证明声明的三个线程已经全部运行完毕,后面代码可以综合三个线程的结果,执行后面的判断
}
int main()
{
//初始化临界区对象
//CRITICAL_SECTION结构对象必须经过InitializeCriticalSection()的初始化后才能使用
InitializeCriticalSection(&cs);
//多线程同步测试
test1();
test2();
//清除临界区对象,释放资源
DeleteCriticalSection(&cs);
system("pause");
}