0
点赞
收藏
分享

微信扫一扫

Windows网络编程——线程

一、创建一个简单的线程

1.创建线程

这个系列的文章使用C++的语法,C也可以 在vs2019环境下代码可正常运行

创建一个程序就创建了一个进程,一个进程自带一个线程 main 可以是主线程 在Windows下创建一个子线程需要调用 windows.h

#include<Windows.h>

使用创建线程函数 CreateThread()

HANDLE h = CreateThread(NULL, 0, ThreadProc, 0, 0, 0);

函数的返回值是一个HANDLE类型的句柄 打开任务管理器,可看见句柄 屏幕截图_20230120_111512.png 这个函数需要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,并且换行,实际是 屏幕截图_20230120_183840.png

解决方法

多个线程无限制的访问同一资源时会发生错误

原子锁

原子锁具有局限性,只能对单个变量进行+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++)太大,会使程序运行一段时间

内核对象

这里不描述

举报

相关推荐

0 条评论