C++ Windows 多线程编程:线程创建、同步与互斥锁详解
本文讲解如何在 Windows 平台下使用 C++ 标准库外的 Win32 API 实现多线程程序。内容涵盖使用 CreateThread 创建新线程,使用 Sleep 控制并发节奏,并重点演示如何通过互斥锁(CreateMutex)解决多线程同时访问共享资源时的竞态条件问题。
Windows 环境下的多线程基础
C++ 标准库早期版本未直接提供跨平台的多线程支持,但在 Windows 操作系统中,开发者可以直接调用 SDK 提供的 Win32 API 来编写多线程程序。核心机制是通过句柄管理线程生命周期与资源同步。
第1步:创建线程
目的: 启动一个新的执行流,使其与主函数(main)并行运行。
入口: windows.h 头文件。
动作: 调用 CreateThread 函数。该函数接收以下关键参数:
lpStartAddress: 线程函数的地址,即新线程执行的入口点。lpParameter: 传递给线程函数的参数指针(通常为void*)。
函数原型如下:
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
第2步:线程执行示例
目的: 观察主线程与子线程的并发执行情况。
操作: 定义一个返回类型为 DWORD 且参数为 LPVOID 的回调函数,并在其中循环输出信息。
以下代码演示了最基础的线程创建:Fun 函数持续输出 "Fun display!",main 函数持续输出 "main display!"。
#include <iostream>
#include <windows.h>
using namespace std;
DWORD WINAPI Fun(LPVOID lpParamter) {
while(1) {
cout << "Fun display!" << endl;
}
}
int main() {
HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);
CloseHandle(hThread);
while(1) {
cout << "main display!" << endl;
}
return 0;
}
第3步:调整并发节奏
目的: 由于 CPU 调度极快,两个线程交替执行导致输出混乱难以观察。引入休眠以便验证并发逻辑。
工具: Sleep(DWORD dwMilliseconds) 函数,参数单位为毫秒。
#include <iostream>
#include <windows.h>
using namespace std;
DWORD WINAPI Fun(LPVOID lpParamter) {
while(1) {
cout << "Fun display!" << endl;
Sleep(1000); // 暂停1秒
}
}
int main() {
HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);
CloseHandle(hThread);
while(1) {
cout << "main display!" << endl;
Sleep(2000); // 暂停2秒
}
return 0;
}
运行上述代码,虽然能清晰看到两行文字交错出现,但常会出现格式错乱(如换行丢失或连续空行)。这是因为 std::cout 并非线程安全的原子操作,两个线程可能在中间切换,导致缓冲区状态不一致。
解决资源竞争:互斥锁同步
当多个线程共同访问同一资源(如屏幕控制台、全局变量等)时,如果不加控制,会导致“竞态条件”(Race Condition)。例如,一个线程正在写入数据,另一个线程恰好读取或修改了该数据,结果将不可预测。解决之道在于使用 互斥量(Mutex) 实现对资源的独占访问。
核心 API 说明
实现同步需要三个关键步骤:创建互斥量、等待获取所有权、释放所有权。
1. 创建互斥量
调用 CreateMutex。
* bInitialOwner: 若为 TRUE,则创建线程立即拥有互斥量;若为 FALSE,则初始为空。
2. 请求资源
调用 WaitForSingleObject。
* dwMilliseconds: 通常设为 INFINITE,表示无限期等待直到获得资源。
3. 释放资源
调用 ReleaseMutex。
* 操作完成后必须释放,否则其他线程将无法继续。
第4步:使用互斥锁修复竞态问题
目的: 确保 Fun 和 main 输出的完整性,避免混行。
操作: 在全局定义互斥量句柄,在执行打印操作前后分别进行获取和释放。
注意:为了防止死锁,务必保证每个成功获取的互斥量最终都被正确释放。
#include <iostream>
#include <windows.h>
using namespace std;
HANDLE hMutex;
DWORD WINAPI Fun(LPVOID lpParamter) {
while(1) {
WaitForSingleObject(hMutex, INFINITE); // 等待锁
cout << "Fun display!" << endl; // 临界区操作
Sleep(1000);
ReleaseMutex(hMutex); // 释放锁
}
}
int main() {
HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);
// 创建名为 "screen" 的互斥量,初始不归属创建者
hMutex = CreateMutex(NULL, FALSE, "screen");
CloseHandle(hThread);
while(1) {
WaitForSingleObject(hMutex, INFINITE); // 等待锁
cout << "main display!" << endl; // 临界区操作
Sleep(2000);
ReleaseMutex(hMutex); // 释放锁
}
return 0;
}
加入互斥锁后,当一个线程正在向屏幕输出字符时,另一个线程会被阻塞在 WaitForSingleObject 处。只有当前线程完成所有输出并调用 ReleaseMutex 后,另一线程才能获得执行权。从而保证了输出的条理性。
总结
在 Windows 下进行 C++ 多线程开发,主要依赖 Win32 API 中的 CreateThread 构建并发流,并使用 CreateMutex 配合 WaitForSingleObject 和 ReleaseMutex 管理共享资源的安全访问。理解这一模式是处理更复杂并发场景(如生产者-消费者模型)的基础。以上就是C++ Win32多线程编程的详细内容,更多关于C++并发编程的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













