• 网络程序设计——VC的多线程编程(线程与进程)


    目录

    一、线程与进程

    1、线程

    2、引用线程的原因

    3、线程与进程的关系 

     4、线程的特点

    二、线程函数的参数传递

    三、多线程与单线程的区别

     四、线程创建函数_beginthread()和_beginthreadex()

    五、终止线程函数

    一、线程与进程

    1、线程

          当从一个进程切换到另一个进程时,需要保护当前进程的状态(主要是虚拟内存映像,文件描述符,寄存器内容等),并恢复将要运行的进程的状态,这不仅消耗CPU的执行时间,还要占用较多的存储空间。

    线程是进程内部的一个执行单元。它只是简单地扩展了进程切换的概念,它从进程间的切换转变成了同一个进程内的函数间的切换。

    2、引用线程的原因

        为了减少进程切换时的时空开销,使操作系统具有更好的并发性,人们在操作系统中又引入了线程的概念。 

    3、线程与进程的关系 

         ① 同一个进程中函数间的切换相对于进程来说所需的开销要小的多,它只需要保存少数几个寄存器、一个堆栈指针以及程序计数器等少量内容。

         ② 线程实现了进程内的并发性。在支持线程的操作系统中,一个进程内至少有一个线程,称为主线程,它无需由用户去主动创建,是由系统自动创建的。系统创建好进程后,实际上就启动执行了该进程的主线程。

         ③进程中除主线程外还可以有多个子个线程。子线程是用户根据需要创建的。

    多个线程之间可以并发执行(包括主线程和各级子线程),一个线程可以创建和撤消另一个线程。

     4、线程的特点

    由于线程之间的相互制约,致使线程在运行中呈现出间断性。

    线程也有就绪、阻塞和运行三种基本状态。

         ① 同一进程中的多线程通常各自完成不同的工作,可以实现并行处理,避免了某项任务长时间占用CPU时间。

         比如:一个线程负责通过网络收发数据,另一个线程完成所需的计算工作,第三个线程来做文件输入输出,当其中一个由于某种原因阻塞后(比如通过网络收发数据的线程等待对方发送数据),另外的线程仍然能执行而不被阻塞。

         ② 线程自己不独自拥有系统资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。

          ③一个进程中的所有线程都在该进程的虚拟地址空间中,共同使用该虚拟地址空间中的全局变量和系统资源,所以线程间的通讯非常方便。

    二、线程函数的参数传递

    1、创建线程时可以给线程传递一个LPVOID类型的参数,该参数为CreateThread()函数的第四个参数。

    2、当参数为一个整型数据时,可将该整型数据强制转换为LPVOID类型,作为实参直接传递给线程函数。

    3、当参数为一个字符串时,则创建线程时的实参传递既可以使用字符数组,也可以使用CString类。使用字符数组时,实参可直接使用字符数组名或指向字符数组的char* 指针;使用CString类时,可将指向CString对象的指针强制转换为LPVOID。

    4、如果需要向线程传送多个数值时,由于线程函数的参数只有一个,所以需要先将它们封装在一个结构体变量中,然后将该变量的指针作为参数传给线程函数。

    三、多线程与单线程的区别

    多线程运行时库与单线程运行时库有两个重大差别:

    (1)类似errno的全局变量,每个线程单独设置一个;这样从每个线程中可以获取正确的错误信息。

    (2)多线程库中的数据结构以同步机制加以保护。这样可以避免访问时候的冲突。

    注:errno变量

            为防止和正常的返回值混淆,C/C++语言的系统调用一般并不直接返回错误码,而是将错误码存入一个名为 errno 的全局变量中,errno 变量以及各种不同错误码的定义均在 文件中。

            如果一个系统调用或库函数调用失败,可以通过读出 errno 的值来确定问题所在,推测程序出错的原因。

     四、线程创建函数_beginthread()和_beginthreadex()

    1. unsigned long _beginthread
    2. (
    3. void( __cdecl *start_address )( void * ), //指向新线程调用的函数
    4. unsigned stack_size, //新线程堆栈的大小,可为0
    5. void *arglist //传递给线程的参数列表,可为NULL
    6. );
    7. unsigned long _beginthreadex
    8. (
    9. void *security, //指向SECURITY_ATTRIBUTES结构,用于决定返回句柄能否被继承
    10. unsigned stack_size,
    11. unsigned (__stdcall * pfnStartAddr) (void *) ,
    12. void *arglist,
    13. unsigned initflag, //若为0,线程立即执行,CREATE_SUSPENDED,则挂起
    14. unsigned *thrdaddr //存放线程ID
    15. );

    五、终止线程函数

           在线程内部停止_beginthread()或_beginthreadex()创建的线程,可分别使用_endthread()函数和_endthreadex()函数,这两个函数的格式如下:

    1. void _endthread( void );
    2. void _endthreadex( unsigned retval );
    3. //参数retval为线程的退出代码。

    如有错误,敬请指正。

    您的收藏与点赞都是对我最大的鼓励和支持!

  • 相关阅读:
    react-to-vue使用教程
    shell脚本之数组
    Mybatis注解开发(超详细)
    m基于中继协助的认知无线电频谱切换机制的matlab仿真分析
    初始I/O及其基本操作
    PHP+MySQL人才招聘小程序系统源码 带完整前端+后端搭建教程
    一个奇葩的线上问题,导致我排查了一天
    SpringCloud和SpringBoot版本对应关系
    【数据结构】详解链表(一)——单链表(动图讲解)
    FANUC机器人实现本地自动运行的相关配置和参数设置
  • 原文地址:https://blog.csdn.net/x20020402/article/details/127430923