VC++深入详解(14):多线程与线程同步(重新修改版)

本文深入探讨了VC++中的多线程编程,讲解了线程的概念及其在进程中的作用。同时,重点阐述了线程同步的重要性,帮助读者理解如何在多线程环境中确保数据安全和程序稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

考虑到内容的连贯性,我对几乎重写了这篇博客,在这一小节,主要介绍线程以及线程间的同步,而把那个聊天工具放到下一节。

什么是程序?程序是计算计指令的集合,它以文件的形式储存在磁盘上。
什么是进程?进程是一个正在运行的程序的实例,是一个程序在其自身的地址空间内中的一次执行活动。因此,一个程序可以对应多个进程,比如我们可以把自己编写的简单的“hello, world”程序执行很多遍。
进程是资源申请、调度很运行的基本单位,因此:

#include <stdio.h>

int a = 0;

int main()
{
	printf("%d",a);
	++a;
	return 0;
}

尽管a是“全局”变量,但假如我们把这个程序执行2遍,每次打印出来的结果都是0。
在Windows系统下,进程有两部分组成:
(1)操作系统用来管理进程的内核对象。
这些对象用来存放进程统计信息。他们是操作系统内部分配的内存块,只能被内核访问使用,用用程序无法找到该数据结构,并直接改变其内容。Windows提供了一些函数来对内核对象进行操作。
(2)地址空间
它包含所有可执行的模块或DLL模块的代码和数据,也包含动态分配的空间。例如线程的栈和堆。
关于进程的知识我们会在后面的章节仔细讲解。


实际上,进程从来不执行任何东西,若要使进程完成某项操作,它必须拥有一个在它的环境中运行的线程,此线程负责执行包含在进程的地址空间中的代码。也就是说,真正完成代码执行的是线程,而进程只是线程的容器。线程是使用系统资源的基本单位。


线程也由两部分组成:
(1)线程的内核对象。操作系统用它来对线程进行管理,存放线程的统计信息。
(2)线程栈。它用于维护线程执行代码时所需要的所有函数和参数的局部变量。


线程只有一个内核对象和一个栈,开销相对较少,因此在编程中经常采用多线程来解决编程问题,而尽量避免创建新的进程。
与线程相关的基本函数包括:
CreateThread:创建线程
CloseHandle:关闭线程句柄。注意,这只会使指定的线程句柄无效(减少该句柄的引用计数),启动句柄的检查操作,如果一个对象所关联的最后一个句柄被关闭了,那么这个对象会从系统中被删除。关闭句柄不会终止相关的线程。


线程是如何运行的呢?这又与你的CPU有关系了,如果你是一个单核CPU,那么系统会采用时间片轮询的方式运行每个线程;如果你是多核CPU,那么线程之间就有可能并发运行了。这样就会出现很多问题,比如两个线程同时访问一个全局变量之类的。它们需要线程的同步来解决。所谓同步,并不是多个线程一起同时执行,而是他们协同步调,按预定的先后次序执行。
Windows下线程同步的基本方法有3种:互斥对象、事件对象、关键代码段(临界区),下面一一介绍:

互斥对象属于内核对象,包含3个成员:
1.使用数量:记录了有多少个线程在调用该对象
2.一个线程ID:记录互斥对象维护的线程的ID
3.一个计数器:前线程调用该对象的次数
与之相关的函数包括:
创建互斥对象:CreateMutex
判断能否获得互斥对象:WaitForSingleObject
对于WaitForSingleObject,如果互斥对象为有信号状态,则获取成功,函数将互斥对象设置为无信号状态,程序将继续往下执行;如果互斥对象为无信号状态,则获取失败,线程会停留在这里等待。等待的时间可以由参数控制。
释放互斥对象:ReleaseMutex
当要保护的代码执行完毕后,通过它来释放互斥对象,使得互斥对象变为有信号状态,以便于其他线程可以获取这个互斥对象。注意,只有当某个线程拥有互斥对象时,才能够释放互斥对象,在其他线程调用这个函数不得达到释放的效果,这可以通过互斥对象的线程ID来判断。


我们看一个例子:

#include <Windows.h>
#include <stdio.h>

//线程函数声明
DWORD WINAPI Thread1Proc(  LPVOID lpParameter);
DWORD WINAPI Thread2Proc(  LPVOID lpParameter);

//全局变量
int tickets = 100;
HANDLE hMutex;

int main()
{
	HANDLE hThread1;
	HANDLE hThread2;
	//创建互斥对象
	hMutex = CreateMutex( NULL,			//默认安全级别
						  FALSE,		//创建它的线程不拥有互斥对象
						  NULL);		//没有名字
	//创建线程1
	hThread1 = CreateThread(NULL,		//默认安全级别
							0,			//默认栈大小
							Thread1Proc,//线程函数 
							NULL,		//函数没有参数
							0,			//创建后直接运行
							NULL
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值