一、创建一个简单的线程
1.创建线程
这个系列的文章使用C++的语法,C也可以 在vs2019环境下代码可正常运行
创建一个程序就创建了一个进程,一个进程自带一个线程 main 可以是主线程 在Windows下创建一个子线程需要调用 windows.h
#include<Windows.h>
使用创建线程函数 CreateThread()
HANDLE h = CreateThread(NULL, 0, ThreadProc, 0, 0, 0);
函数的返回值是一个HANDLE类型的句柄
打开任务管理器,可看见句柄
这个函数需要6个参数
CreateThread(NULL, 0, ThreadProc, 0, 0, 0) 除了ThreadProc其他的都可以填0,NULL也可以为0
ThreadProc是回调函数,可以理解为子线程的程序,自定义 ThreadProc函数
#include<iostream>
#include<Windows.h>
using namespace std;
DWORD WINAPI ThreadProc(LPVOID lp) {
return 0;
}
int main()
{
// 创建线程,返回句柄
HANDLE h = CreateThread(NULL, 0, ThreadProc, 0, 0, 0);
return 0;
}
函数返回类型是DWORD,即unsigned long WINAPI表示是wins的函数 参数 LPVOID lp, LPVOID就是void* 在CreateThread()六个参数中 NULL, 0, ThreadProc, 0, 0, 0 ThreadProc后面那个参数就是ThreadProc()的参数
#include<iostream>
#include<Windows.h>
using namespace std;
unsigned long WINAPI ThreadProc(void* lp) {
return 0;
}
int main()
{
// 创建线程,返回句柄
HANDLE h = CreateThread(NULL, 0, ThreadProc, 0, 0, 0);
return 0;
}
2.给线程添加任务
我现在需要计算两个式子
1.计算1+2+······+100 2.计算100+101+······+200
不用多线程也能做,这里用两个线程做
主线程计算1+2+······+100 子线程计算100+101+······+200
#include<iostream>
#include<Windows.h>
using namespace std;
DWORD WINAPI ThreadProc(LPVOID lp) {
int* b = (int*)lp;
for (int i = 100; i < 201; i++)
{
*b += i;
}
return 0;
}
int main()
{
// 创建线程,返回句柄
int a = 0, b = 0;
HANDLE h = CreateThread(NULL, 0, ThreadProc, &b, 0, 0);
for (int i = 1; i < 101; i++)
{
a += i;
}
WaitForSingleObject(h, INFINITE);
cout << a << endl;
cout << b << endl;
CloseHandle(h);
return 0;
}
子线程写在ThreadProc()中 主线程写在main()中 先执行主线程
释放线程,和new一块空间delete一样
CloseHandle(h);
下面将任务改变:
计算1+···+200
#include<iostream>
#include<Windows.h>
using namespace std;
DWORD WINAPI ThreadProc(LPVOID lp) {
int* b = (int*)lp;
for (int i = 101; i < 201; i++)
{
*b += i;
}
return 0;
}
int main()
{
// 创建线程,返回句柄
int a = 0;
HANDLE h = CreateThread(NULL, 0, ThreadProc, &a, 0, 0);
for (int i = 1; i < 101; i++)
{
a += i;
}
//WaitForSingleObject(h, INFINITE);
cout << a << endl;
// cout << b << endl;
CloseHandle(h);
return 0;
}
上面的程序将1+··200的值给a 程序的结果: # 5050 # 这肯定不对,在主线程结束时分配给主线程的时间片还未结束,导致子线程未启动,使用
WaitForSingleObject(h, INFINITE);// 上个程序中注释掉的地方
让主线程结束时等等子线程,最后20100
二、线程间的同步
由于访问了同一个变量,导致冲突了,在主线程或子线程还未结束时,另一个线程的时间片就到了 给一个例子
#include<iostream>
#include<Windows.h>
using namespace std;
DWORD WINAPI ThreadProc(LPVOID lp) {
for (int i = 101; i < 201; i++)
{
cout << "in child" << endl;
}
return 0;
}
int main()
{
// 创建线程,返回句柄
int a = 0;
HANDLE h = CreateThread(NULL, 0, ThreadProc, &a, 0, 0);
for (int i = 1; i < 101; i++)
{
cout << "in father" << endl;
}
//WaitForSingleObject(h, INFINITE);
cout << a << endl;
// cout << b << endl;
CloseHandle(h);
return 0;
}
打印的结果应该是先father在child,并且换行,实际是
解决方法
多个线程无限制的访问同一资源时会发生错误
原子锁
原子锁具有局限性,只能对单个变量进行+1或-1
InterlockedIncrement();// 函数需要一个unsigned int类型的参数,自动+1
#include<iostream>
#include<Windows.h>
using namespace std;
unsigned int g;
DWORD WINAPI ThreadProc(LPVOID lp) {
for (int i = 101; i < 201; i++)
{
InterlockedIncrement(&g);
}
return 0;
}
int main()
{
HANDLE h = CreateThread(NULL, 0, ThreadProc, 0, 0, 0);
for (int i = 1; i < 101; i++)
{
InterlockedIncrement(&g);
}
WaitForSingleObject(h, INFINITE);
cout << g << endl;
// cout << b << endl;
CloseHandle(h);
return 0;
}
结果 # 200 # 正确的,200次
InterlockedDecrement();// 自动-1
程序只要将上面的函数名改一下,并给g赋值200 ,结果为 # 0 #
临界区
相比于原子锁只能+1 -1,临界区可以做一一系列事情 使用
// 创建临界区对象
CRITICAL_SECTION g_sec;// 使用CRITICAL_SECTION
// 初始化临界区对象
InitializeCriticalSection(&g_sec);
// 进入临界区
EnterCriticalSection(&g_sec);
....// 内容
// 离开临界区
LeaveCriticalSection(&g_sec);
// 释放
DeleteCriticalSection(&g_sec);
例
#include<iostream>
#include<Windows.h>
using namespace std;
// 全局变量
unsigned int g = 200;
//临界区
CRITICAL_SECTION g_sec;
DWORD WINAPI ThreadProc(LPVOID lp) {
for (int i = 1; i < 100000001; i++)
{
EnterCriticalSection(&g_sec);
g++;
LeaveCriticalSection(&g_sec);
}
return 0;
}
int main()
{
InitializeCriticalSection(&g_sec);
HANDLE h = CreateThread(NULL, 0, ThreadProc, 0, 0, 0);
for (int i = 1; i < 100000001; i++)
{
EnterCriticalSection(&g_sec);
g++;
LeaveCriticalSection(&g_sec);
}
WaitForSingleObject(h, INFINITE);
cout << g << endl;
// cout << b << endl;
CloseHandle(h);
DeleteCriticalSection(&g_sec);
return 0;
}
for (int i = 1; i < 100000001; i++)太大,会使程序运行一段时间
内核对象
这里不描述