热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

c多线程编程,c多线程编程实例

c多线程编程,c多线程编程实例,VC多线程编程详解本文主要介绍了VC多线程编程,并以实例的形式详细分析了多线程编程的原理和实现方法。有一定的参考价值,有需要的朋友可以参考一下。本文

c 多线程编程,c多线程编程实例,VC多线程编程详解

本文主要介绍了VC多线程编程,并以实例的形式详细分析了多线程编程的原理和实现方法。有一定的参考价值,有需要的朋友可以参考一下。

本文用实例讲述VC多线程编程的概念和技巧,与大家分享,供大家参考。具体分析如下:

一、多线程编程要点

它是一个线程进程的执行路径,包含独立的堆栈和CPU寄存器状态。每个线程共享所有进程资源,包括打开的文件、信号标识和动态分配的内存。一个进程中的所有线程都使用相同的地址空间,这些线程的执行由系统调度程序控制,系统调度程序决定哪个线程可以执行以及何时执行。有一个线程优先级,优先级较低的线程必须等到优先级较高的线程执行完。在多处理器机器上,调度器可以将多个线程放在不同的处理器上运行,这样可以平衡处理器的任务,提高系统的运行效率。

Windows是一个多任务操作系统,在一个Windows进程中包含一个或多个线程。32位Windows环境下的Win32 API提供了多线程应用程序开发所需的接口函数,VC中提供的标准C库也可以用来开发多线程应用程序。相应的MFC类库封装了多线程编程类,用户可以根据应用的需求和特点选择相应的工具。为了让大家充分了解Windows多线程编程技术,本文将重点介绍如何在Win32 API和MFC中编写多线程程序。

Win32模式下多线程编程的原理与MFC类库支持的一致,一个进程的主线程可以随时创建一个新线程。当线程结束时,自动终止线程;当进程结束时,所有线程都被终止。所有活动线程共享进程的资源,所以在编程时需要考虑多个线程访问同一个资源时的冲突问题。当一个线程正在访问一个进程对象,而另一个线程想要改变该对象时,可能会产生错误的结果。这种冲突应该在编程时解决。

二、Win32 API下的多线程编程

Win32 API是Windows操作系统内核和应用程序之间的接口。它封装了内核提供的函数,应用程序通过调用相关函数获得相应的系统函数。为了给应用程序提供多线程功能,Win32 API函数集提供了一些处理多线程程序的函数集。用Win32 API直接编程有很多优点:基于Win32的应用程序执行代码小,运行效率高,但需要程序员编写更多的代码,管理系统为程序提供的所有资源。直接用Win32 API编写程序,需要程序员对Windows系统内核有一定的了解,这将占用程序员大量的时间来管理系统资源,从而降低了他们的工作效率。

1. 用Win32函数创建和终止线程

Win32库提供操作多线程的函数,包括创建线程、终止线程和建立互斥。在应用程序的主线程或其他活动线程中创建新线程的功能如下:

如下:Handle CreateThread(LP security _ attributes LP thread属性,dword dwstack大小,LP thread _ start _ routine LP start address,lpvoid lpparameter,dword dwcreationflags,lpd word LP threadid);

如果创建成功,则返回线程的句柄;否则,返回NULL。创建新线程后,该线程开始执行。但是,如果在dwCreationFlags中使用了CREATE_SUSPENDED特性,那么线程不会立即执行,而是先挂起,然后调用ResumeThread后再启动线程。在这个过程中,可以调用下面的函数来设置线程的优先级:

如下:Bool Sethread Priority(handle hthread,int n Priority);

当调用线程的函数返回时,线程自动终止。如果需要在线程执行期间终止线程,可以调用函数:

如下:VOID exit thread(DWORD dwExitCode);

如果线程在线程外终止,可以调用下面的函数:

如下:Bool terminate thread(处理hthread,dword dwexit代码);

但需要注意的是,该功能可能会造成系统不稳定,线程占用的资源不会被释放。因此,一般情况下,不建议使用该功能。

如果要终止的线程是进程中的最后一个线程,则应该在线程终止后终止相应的进程。

2. 线程的同步

在线程体中,如果线程是完全独立的,并且在数据访问等资源操作上与其他线程没有冲突,那么可以按照通常的单线程方式进行编程。但是,在多线程中往往不是这样,线程经常要同时访问一些资源。访问共享资源引起的冲突是不可避免的。为了解决这个线程同步问题,Win32 API提供了多种同步控制对象,帮助程序员解决共享资源访问冲突。在介绍这些同步对象之前,先介绍一下等待函数,因为这个函数是用于所有控制对象的访问控制的。

Win32 API提供了一组等待函数,可以让线程阻塞自己的执行。这些函数在其参数中从一个或多个同步对象生成信号,否则它们将只在指定的等待时间后返回。等待函数不返回时,线程处于等待状态,此时线程只消耗一点点CPU时间。等待功能不仅可以保证线程的同步,还可以提高程序的运行效率。最常用的等待功能有:

如下:DWORD waitforsingleobject(handle h handle,DWORD dw milliseconds);

WaitForMultipleObject函数可用于同时监视多个同步对象。这个函数的声明是:

如下:Dword Waitformula对象(Dword ncount,const handle * LP handles,bool bwaitall,Dword dw millions);

(1)互斥体对象

当互斥对象不被任何线程拥有时,它的状态有一个信号,但当它被拥有时没有信号。互斥对象适用于协调多个线程对共享资源的互斥访问。您可以按如下方式使用该对象:

首先,建立互斥对象以获得句柄:

如下:HANDLE create mutex();

然后,在线程可能发生冲突的区域之前(即访问共享资源之前)调用WaitForSingleObject,将句柄传递给函数,请求占用互斥对象:

如下:dwwaitresult=waitforsingleobject(hmutex,5000 l);

共享资源访问结束,释放互斥对象的占用:

如下:release mutex(hMutex);

一个互斥对象一次只能被一个线程占用。当一个互斥对象被一个线程占用时,如果另一个线程想占用它,必须等到前一个线程被释放后才能成功。

(2)信号对象

Signal允许多个线程同时访问共享资源,并指定创建对象时可以同时访问的最大线程数。当线程成功申请访问时,signal对象中的计数器减一,调用ReleaseSemaphore函数后,signal对象中的计数器加一。其中计数器值大于或等于0,但小于或等于创建时指定的最大值。如果应用程序在创建信号对象时将其计数器的初始值设置为0,它会阻塞其他线程并保护资源。初始化完成后,调用ReleaseSemaphore函数将其计数器增加到最大值,即可进行正常访问。您可以按如下方式使用该对象:

首先,创建信号对象:

如下:HANDLE CreateSemaphore();

或者打开一个信号对象:

如下:HANDLE open semaphore();

然后,在线程访问共享资源之前调用WaitForSingleObject。

共享资源访问完成后,应该释放对信号对象的占用:

如下:release semaphore();

(3)事件对象

事件是最简单的同步对象,包括有信号和无信号两种状态。在线程访问资源之前,它需要等待事件发生。这时,使用事件对象是最合适的。例如,只有在通信端口缓冲器中接收到数据之后,监控线程才被激活。

该事件是用CreateEvent函数创建的。这个函数可以指定事件对象的类和事件的初始状态。如果是手动复位事件,它将始终保持信号状态,直到使用复位事件功能将其复位为非信号事件。如果是自动复位事件,在单个等待线程被释放后,其状态会自动变为静默。SetEvent可用于将事件对象设置为信号状态。创建事件时,可以命名对象,以便其他进程中的线程可以使用OpenEvent函数打开具有指定名称的事件对象的句柄。

(4)排斥区对象

在排除区异步执行时,只能在同一个进程的线程间共享资源处理。虽然此时可以使用上述几种方法,但是使用禁区的方法使同步管理更加有效。

使用时,先定义一个CRITICAL_SECTION结构排除区对象,在使用进程前调用以下函数初始化对象:

如下:void初始化器临界段(LP critical _ section);

当一个线程使用exclusion zone时,调用函数:EnterCriticalSection或TryEnterCriticalSection

当需要占用或退出禁区时,调用函数LeaveCriticalSection释放对禁区对象的占用,供其他线程使用。

三、基于MFC的多线程编程

它是微软的VC开发集成环境中提供给程序员的基础函数库。它将Win32 API封装在类库中,以类的形式提供给开发者。由于其快速、简单、功能强大的特点,深受开发者的喜爱。所以应用开发推荐使用MFC类库。

VC附带的MFC类库提供了对多线程编程的支持,基本原理与基于Win32 API的设计一致。但是,因为MFC封装了同步对象,所以实现起来更方便,并且避免了对象句柄管理的繁琐工作。

在MFC中,有两种线程:工作线程和用户界面线程。工作线程与前述线程相同,用户界面线程是可以接收用户输入并处理事件和消息的线程。

1. 工作线程

工作线程编程比较简单,设计思路基本和上面说的一样:一个基本函数代表一个线程,线程创建启动后,线程进入运行状态;如果线程使用共享资源,它们需要同步资源。通过这种方式,可以在线程创建和启动时调用该函数:

如下:CWinThread*AfxBeginThread(

AFX_THREADPROC pfnThreadProc,

LPVOID pParam,

int n PRIORITY=THREAD _ PRIORITY _ NORMAL,

UINT nStackSize=0,

DWORD dwCreateFlags=0,

LP security _ ATTRIBUTES lpSecurityAttrs=NULL);

参数pfnThreadProc是一个线程执行器函数,其原型是uint线程函数(lpvoid p param)。

参数pParam是传递给执行函数的参数;

参数nPriority是线程执行权限,可选值:

线程优先级正常、线程优先级最低、线程优先级最高、线程优先级空闲。

参数dwCreateFlags是创建线程时的标志。可以取CREATE_SUSPENDED的值,表示线程创建后处于挂起状态,调用ResumeThread函数后线程继续运行,或者取值“0”表示线程创建后处于运行状态。

返回值是CWinThread类对象的指针,其成员变量m_hThread是线程句柄。在Win32 API模式下,线程操作的函数参数需要线程句柄,所以线程创建后,所有Win32 API函数都可以用来对pWinThread-m_Thread线程执行相关操作。

注意:在类对象中创建和启动线程时,线程函数应该定义为类外的全局函数。

2. 用户接口线程

基于MFC的应用程序有一个application对象,它是CWinApp派生类的一个对象,这个对象代表应用程序进程的主线程。当线程完成执行并退出线程时,进程自动结束,因为进程中没有其他线程。CWinApp类派生自CWinThread,是用户界面线程的基类。当我们编写用户界面线程时,我们需要从CWinThread中派生出自己的线程类,而ClassWizard可以帮助我们做到这一点。

首先,使用ClassWizard派生一个新类,并将基类设置为CwinThread。注意:类的DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE宏是必需的,因为类的对象需要在创建线程时动态创建。如果需要,初始化和结束代码可以分别放在该类的InitInstance和ExitInstance函数中。如果你需要创建一个窗口,你可以在InitInstance函数中完成。然后创建一个线程并启动它。有两种方法可以创建用户界面线程。MFC提供了两个版本的AfxBeginThread函数,其中一个用于创建用户界面线程。第二种方法分两步:首先调用thread类的构造函数创建一个thread对象;其次,调用CWinThread:CreateThread函数来创建线程。在线程建立和启动之后,它在线程功能的执行期间保持有效。如果它是一个线程对象,线程在对象被删除之前被终止。CWinThread已经为我们完成了线程结束工作。

3. 线程同步

前面我们介绍了Win32 API提供的几个与线程同步相关的对象,这些对象被类封装在MFC类库中。它们有一个共同的基类CSyncObject,对应关系为:Semaphore对应CSemaphore,Mutex对应CMutex,Event对应ce Event,CriticalSection对应CCriticalSection。此外,MFC还封装了两个等待函数,分别是CSingleLock和CMultiLock。由于四个对象的用法相似,这里以CMutex为例进行说明:

创建CMutex对象:

如下:CMutex互斥体(FALSE,NULL,NULL);

或者复制如下代码:CMutex互斥体;

当每个线程都想要访问共享资源时,请使用以下代码:

如下:CSingleLock sl(互斥);

sl。lock();

如果(sl。IsLocked())

//在共享资源上操作.

sl。unlock();

四、结束语

如果用户的应用需要同时处理多个任务,多线程是理想的选择。在这里提醒一下,多线程编程的时候要注意资源共享和多线程调试的问题。

希望这篇文章对大家的VC编程有所帮助。



推荐阅读
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文详细介绍了云服务器API接口的概念和作用,以及如何使用API接口管理云上资源和开发应用程序。通过创建实例API、调整实例配置API、关闭实例API和退还实例API等功能,可以实现云服务器的创建、配置修改和销毁等操作。对于想要学习云服务器API接口的人来说,本文提供了详细的入门指南和使用方法。如果想进一步了解相关知识或阅读更多相关文章,请关注编程笔记行业资讯频道。 ... [详细]
  • 基于事件驱动的并发编程及其消息通信机制的同步与异步、阻塞与非阻塞、IO模型的分类
    本文介绍了基于事件驱动的并发编程中的消息通信机制,包括同步和异步的概念及其区别,阻塞和非阻塞的状态,以及IO模型的分类。同步阻塞IO、同步非阻塞IO、异步阻塞IO和异步非阻塞IO等不同的IO模型被详细解释。这些概念和模型对于理解并发编程中的消息通信和IO操作具有重要意义。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 如何提高PHP编程技能及推荐高级教程
    本文介绍了如何提高PHP编程技能的方法,推荐了一些高级教程。学习任何一种编程语言都需要长期的坚持和不懈的努力,本文提醒读者要有足够的耐心和时间投入。通过实践操作学习,可以更好地理解和掌握PHP语言的特异性,特别是单引号和双引号的用法。同时,本文也指出了只走马观花看整体而不深入学习的学习方式无法真正掌握这门语言,建议读者要从整体来考虑局部,培养大局观。最后,本文提醒读者完成一个像模像样的网站需要付出更多的努力和实践。 ... [详细]
  • 本文讨论了微软的STL容器类是否线程安全。根据MSDN的回答,STL容器类包括vector、deque、list、queue、stack、priority_queue、valarray、map、hash_map、multimap、hash_multimap、set、hash_set、multiset、hash_multiset、basic_string和bitset。对于单个对象来说,多个线程同时读取是安全的。但如果一个线程正在写入一个对象,那么所有的读写操作都需要进行同步。 ... [详细]
author-avatar
Mayuki命_103
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有