Windows网络自学的第一天:创建线程

这篇具有很好参考价值的文章主要介绍了Windows网络自学的第一天:创建线程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、创建线程

CreateThread函数:

 下面是示例:

​编辑

ThreadProc函数解释:

    DWORD的本质是 unsigned long    PVOID的本质是 void*

二、线程的终止

1.WaitForSingleObject()函数:

示例如下:

2.ExitThread()函数:

示例如下:

3.TerminateThread()函数:

4.CloseHandle()函数:

5.正常return 0;

三、线程的恢复与挂起

1.挂起线程:

①SuspendedThread()函数:

示例如下:

 ②CreateThread()的第五个参数设为CEREATE_SUSPENDED

 四、线程的优先级


一、创建线程

CreateThread函数:

        该函数用于创建一个新的线程并在其上运行指定的函数,其返回值是HANDLE类型(句柄),原型如下:

HANDLE CreateThread(
            LPSECURITY_ATTRIBUTES   lpThreadAttributes,
            SIZE_T                  dwStackSize,
            LPTHREAD_START_ROUTINE  lpStartAddress,
            LPVOID                  lpParameter,
            DWORD                   dwCreationFlags,
            LPDWORD                 lpThreadId
        );

        第一个参数:
            指向SECURITY_ATTRIBUTES形态的结构的指针,表示线程内核对象的安全属性
                windows 98忽略该参数,windows NT中设为NULL表示使用默认安全属性

        第二个参数:
            初始该线程的堆栈大小,以字节为单位,默认为0即使用默认大小(1MB),在任何情况下,OS会动态延长堆栈大小

        第三个参数:
            是一个指向线程函数的指针。线程将从此函数的入口点开始执行。
            函数名称无限制,但必须是以下形式声明:
                DWORD WINAPI ThreadProc(PVOID pParam);

        第四个参数:
            传递给线程函数(第三个函数的参数)的参数,是一个指针类型。

        第五个参数:
            线程的创建标志,通常设置为0即可,可选参数如下:
                0(或CREATE_SUSPENDED):默认值,创建线程后立即执行线程函数。

                CREATE_SUSPENDED:创建线程后暂停线程的执行,需要通过ResumeThread激活线程。

                CREATE_DETACHED:创建一个分离的线程,不需要手动释放线程资源。

                STACK_SIZE_PARAM_IS_A_RESERVATION:将dwStackSize参数解释为堆栈的保留大小。

                CREATE_NEW_CONSOLE:创建一个新的控制台窗口,使线程在独立的控制台环境中运行。

                CREATE_UNICODE_ENVIRONMENT:使用Unicode字符集解析环境字符串。

        第六个参数:
            一个指向DWORD类型的指针,用于接收新线程的标识符(ID)
            将返回线程的ID号,传入NULL表示不需要返回该线程ID号
 

 下面是示例:

#include <iostream>
#include <windows.h> //调用windows API的头文件
using namespace std;

//线程函数,格式固定
DWORD WINAPI ThreadProc(PVOID lp){
    //线程的主体
    //…………
    return 0;
};


int main()
{
    CreateThread(NULL, 0, ThreadProc, NULL, 0, 0);

    return 0;
}
Windows网络自学的第一天:创建线程,Windows网络自学,windows,多线程,c++
ThreadProc函数解释:

        该函数即线程入口,ThreadProc 和 lp一样, 名字随意, ThreadProc函数本身作为CreateThread函数的第三个参数,该函数参数由CreateThread函数的第四个参数传入

    DWORD的本质是 unsigned long
    PVOID的本质是 void*

注意:在多线程环境中,全局变量是所有线程共享的,这意味着多个线程可以同时访问和修改这些全局变量。因为线程是并发的,所以当一个线程在执行过程中修改了全局变量的值时,其他线程在访问同一全局变量时可能会读取到这个修改后的值。

如果一个线程使用new在堆上分配了内存,并在线程执行过程中释放了这块内存,那么其他线程在访问这块内存时可能会遇到悬挂指针(dangling pointer)或无效内存访问的问题

因此,在多线程编程中,对于共享的资源,包括全局变量和动态分配的内存(如new操作),必须非常小心。应该通过合适的同步机制(例如互斥锁、条件变量等)来确保多个线程对这些资源的安全访问。这样可以避免潜在的竞态条件和访问无效内存的问题。

在处理动态内存时,最好的做法是由创建它的线程负责释放内存,而不是在其他线程中释放。此外,可以使用智能指针(例如std::shared_ptrstd::unique_ptr)来管理动态内存,这样可以避免手动释放内存的问题。

二、线程的终止

1.WaitForSingleObject()函数:

函数原型如下:

DWORD WaitForSingleObject(
  HANDLE hHandle,  // 要等待的内核对象的句柄,这里是线程句柄
  DWORD  dwMilliseconds // 等待的时间,以毫秒为单位,INFINITE 表示无限等待
);

第二个参数 dwMilliseconds 表示等待的时间,以毫秒为单位。这个参数控制函数在等待对象状态变化时的行为:

  • 如果 dwMilliseconds 的值为 INFINITE(-1),则 WaitForSingleObject 会一直阻塞,直到内核对象的状态发生变化。
  • 如果 dwMilliseconds 的值为 0,则函数立即检查内核对象的状态,然后返回,不会等待。

其他正整数值表示等待的毫秒数。如果在指定的时间内对象的状态没有发生变化,函数会返回一个值,表示等待超时。 

示例如下:

#include <iostream>
#include <windows.h>
using namespace std;

DWORD WINAPI myProThread(PVOID lp)
{
    //ExitThread(0);    强制终止线程
    Sleep(5000);    //Windows 下 Sleep 以毫秒为单位,这里是休眠 5 秒
    return 0;
}

int main()
{
    DWORD id = 0;
    HANDLE handle = CreateThread(NULL, 0, myProThread, NULL, 0, &id);

    DWORD result = WaitForSingleObject(handle, 1);    //这里是设定等待线程1毫秒,为了测定超时

    if (result == WAIT_OBJECT_0)
    {
        // 线程结束,可以继续处理
        cout << "线程结束" << endl;
    }
    else if (result == WAIT_TIMEOUT)
    {
        // 超时,可以采取相应的措施
        cout << "超时了" << endl;
    }
    else if (result == WAIT_FAILED)
    {
        // 函数调用失败,可以通过 GetLastError() 获取错误信息
        DWORD dwError = GetLastError();
        cout << "线程错误代码为:" << dwError << endl;
    }

    cout << "该线程的ID是:" << id << endl;

    CloseHandle(handle);    //关闭线程句柄

    return 0;
}

// 等待线程结束

Windows网络自学的第一天:创建线程,Windows网络自学,windows,多线程,c++

2.ExitThread()函数:

ExitThread 函数可以用于在线程函数内部直接退出线程。但是需要注意,使用此函数会终止线程的执行,不会调用线程的析构函数,也不会释放线程所占用的资源。这可能会导致资源泄漏或程序的不稳定性。

只能在线程内使用,终止该线程

示例如下:

代码:

#include <iostream>
#include <windows.h>
using namespace std;

DWORD WINAPI myProThread(PVOID lp)
{
    ExitThread(0);   //强制终止线程
    Sleep(5000);    //Windows 下 Sleep 以毫秒为单位,这里是休眠 5 秒
    return 0;
}

int main()
{
    DWORD id = 0;
    HANDLE handle = CreateThread(NULL, 0, myProThread, NULL, 0, &id);

    DWORD result = WaitForSingleObject(handle, 1);    //这里是设定等待线程1毫秒,为了测定超时

    if (result == WAIT_OBJECT_0)
    {
        // 线程结束,可以继续处理
        cout << "线程结束" << endl;
    }
    else if (result == WAIT_TIMEOUT)
    {
        // 超时,可以采取相应的措施
        cout << "超时了" << endl;
    }
    else if (result == WAIT_FAILED)
    {
        // 函数调用失败,可以通过 GetLastError() 获取错误信息
        DWORD dwError = GetLastError();
        cout << "线程错误代码为:" << dwError << endl;
    }

    cout << "该线程的ID是:" << id << endl;

    CloseHandle(handle);    //关闭线程句柄

    return 0;
}

// 等待线程结束

 运行结果:

 Windows网络自学的第一天:创建线程,Windows网络自学,windows,多线程,c++

3.TerminateThread()函数:

TerminateThread 函数可以用来强制终止一个线程。然而,这个函数不安全,因为它会立即终止线程的执行,而不管线程正在做什么。这可能会导致未释放的资源,不稳定的状态,以及可能影响整个进程的问题。推荐避免使用这个函数。

可以在线程外使用,终止指定线程

这里不做示例,只提供函数如何使用:

TerminateThread(hThread, 0);        //第一个参数是线程句柄,第二个参数是退出码(无意义)

4.CloseHandle()函数:

如果你有线程的句柄,可以使用 CloseHandle 函数来关闭线程句柄。这不会终止线程,但会释放句柄所占用的资源。这个函数的主要作用是清理句柄,而不是终止线程。

注:在关闭线程句柄之前,通常应该确保线程已经退出或者至少没有使用线程句柄引用了线程。

5.正常return 0;

不做赘述。

三、线程的恢复与挂起

1.挂起线程:

PS:下列代码输出求挂起数时,加了1。

①SuspendedThread()函数:

参数为线程句柄,返回值为先前的挂起数(即调用该函数次数)

示例如下:

代码:

#include <iostream>
#include <windows.h>
using namespace std;

DWORD WINAPI myProThread(PVOID lp)
{
    //ExitThread(0);   //强制终止线程
    Sleep(5000);    //Windows 下 Sleep 以毫秒为单位,这里是休眠 5 秒
    return 0;
}

int main()
{
    DWORD id = 0;
    HANDLE handle = CreateThread(NULL, 0, myProThread, NULL, 0, &id);   //第五个参数表示创建完成时挂起线程

    cout << "该线程的ID是:" << id << endl;

    DWORD result = WaitForSingleObject(handle, 3000);    //这里是设定等待线程1毫秒,为了测定超时

    
    // 挂起线程
    DWORD suspendCount = SuspendThread(handle);
    
    cout << "初始挂起数为:"  << suspendCount + 1 << endl;

    // 检查是否成功挂起线程
    if (suspendCount != -1) {
        cout << "线程已挂起" << endl;
    } else {
        cerr << "无法挂起线程" << endl;
    }

    if (result == WAIT_OBJECT_0)
    {
        // 线程结束,可以继续处理
        cout << "线程结束" << endl;
    }
    else if (result == WAIT_TIMEOUT)
    {
        // 超时,可以采取相应的措施
        cout << "超时了" << endl;
    }
    else if (result == WAIT_FAILED)
    {
        // 函数调用失败,可以通过 GetLastError() 获取错误信息
        DWORD dwError = GetLastError();
        cout << "线程错误代码为:" << dwError << endl;
    }


    CloseHandle(handle);    //关闭线程句柄


    return 0;
}

结果:

Windows网络自学的第一天:创建线程,Windows网络自学,windows,多线程,c++

 ②CreateThread()的第五个参数设为CEREATE_SUSPENDED

代码同上,只是在创建线程时,把第五个参数设为CEREATE_SUSPENDED了

结果:

Windows网络自学的第一天:创建线程,Windows网络自学,windows,多线程,c++

 四、线程的优先级

在 Windows 下,C++ 程序可以使用线程库(Thread Library)来创建和管理线程。在 Windows 中,线程优先级用于确定操作系统在有多个线程要执行时,如何进行线程调度。Windows 提供了一组函数和常量来设置和获取线程的优先级。以下是关于 Windows 下 C++ 线程优先级的重要信息:

1. **线程优先级范围:** 在 Windows 系统中,线程的优先级范围通常是从 0(最低优先级)到 31(最高优先级)。

2. **默认优先级:** 当创建一个新线程时,它默认会继承创建它的线程的优先级。

3. **设置线程优先级:** 可以使用 `SetThreadPriority` 函数来设置线程的优先级。该函数的原型如下:


   BOOL SetThreadPriority(
     HANDLE hThread,
     int    nPriority
   );

     - `hThread`:要设置优先级的线程句柄。
     - `nPriority`:要设置的优先级,可以是以下常量之一:
     - `THREAD_PRIORITY_IDLE`
     - `THREAD_PRIORITY_LOWEST`
     - `THREAD_PRIORITY_BELOW_NORMAL`
     - `THREAD_PRIORITY_NORMAL`
     - `THREAD_PRIORITY_ABOVE_NORMAL`
     - `THREAD_PRIORITY_HIGHEST`
     - `THREAD_PRIORITY_TIME_CRITICAL`

4. **获取线程优先级:** 可以使用 `GetThreadPriority` 函数来获取线程的当前优先级。该函数的原型如下:


   int GetThreadPriority(
     HANDLE hThread
   );


 - `hThread`:要查询优先级的线程句柄。

需要注意的是,虽然可以通过设置线程的优先级来影响线程的调度,但是过度使用优先级可能会导致问题,如饥饿、不公平调度等。正确地使用同步机制和合适的线程优先级,以确保程序的稳定性和可预测性,是良好的多线程编程实践的一部分。

在实际开发中,除非你有明确的需求,一般不建议频繁地改变线程的优先级,而是让操作系统自行管理线程调度,以确保整个系统的平稳运行。文章来源地址https://www.toymoban.com/news/detail-624178.html

到了这里,关于Windows网络自学的第一天:创建线程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 学习Python的第一天(下载Python环境和工具Pycharm)

    下载工具  PyCharm Community Edition 2023.3.4 下载环境 Python3.10.4 目录 1.环境Python下载 1.1 Python环境变量下载网址:   1.2 下载步骤 2.工具Pycharm下载 2.1 pycharm下载网址  2.2 pycharm下载步骤 Python Releases for Windows | Python.org 这里我将列举我正在使用的版本 Python3.10.4 下载过程如果是其他版本

    2024年03月26日
    浏览(40)
  • Java使用LocalDate获取某个月的第一天和最后一天日期

    以一个月为周期进行查询时,如果用户没有选择查询的月份,我们想要默认查询当月或上个月的数据,这时,如何获取到一个月的第一天和最后一天日期呢? 以下介绍两种方式采用LocalDate格式日期的实现,以及采用LocalDateTime格式日期的实现。直接上代码! 输出结果为:

    2023年04月20日
    浏览(49)
  • JAVA获取本日,本日开始时间本周、本月和本年的第一天和最后一天

    这个是我自己再项目中写到的 可以借鉴 打印运行结果如下

    2024年02月13日
    浏览(25)
  • 热爱python的第一天:初识python,搭建python环境,运行第一个python小程序

     目录 专栏导读  1 初始python python 概述 python的应用领域   应用python的公司  2 搭建python 开发环境  2.1 安装python(以windows 系统为例)(1)下载安装包  (2) 下载保存后打开文件夹点击以管理员身份运行  (3)选择自定义安装,同时将add python3.9 to path勾上。  (4)测试

    2024年02月13日
    浏览(30)
  • LeetCode 1997.访问完所有房间的第一天:动态规划(DP)——4行主要代码(不需要什么前缀和)

    力扣题目链接:https://leetcode.cn/problems/first-day-where-you-have-been-in-all-the-rooms/ 你需要访问  n 个房间,房间从 0 到 n - 1 编号。同时,每一天都有一个日期编号,从 0 开始,依天数递增。你每天都会访问一个房间。 最开始的第 0 天,你访问  0 号房间。给你一个长度为 n 且 下标从

    2024年04月14日
    浏览(26)
  • 项目创建第一天 搭建前端环境

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 提示:这里可以添加本文要记录的大概内容: 前端环境 Hbuider x + elementui 转发 nginx 后台环境 springcloud 提示:以下是本篇文章正文内容,下面案例可供参考 示例:构建代码的土壤 导入 安装路由 在根目录

    2024年02月03日
    浏览(26)
  • 2023-5-6第一次创建博客的第一篇文章

    关于最近学习记下来的一些要点以及模糊的地方总结 对象类型和引用类型可以用链式结构 2进制是toBinaryString 10进制是Decimal 16进制是toHexString 8进制是octal final 1.修饰类 不能被继承 2.修饰方法 不能被重写,能被重载 3.修饰变量 值不可被重新赋值 属性可以被修改 4.修饰引用数据

    2024年02月03日
    浏览(37)
  • 学C的第十一天【查看汇编代码一步步了解 函数栈帧(栈区局部变量)的创建和销毁】

    ========================================================================= 相关代码gitee自取: C语言学习日记: 加油努力 (gitee.com) ========================================================================= 接上期: 学C的第十天(继续深入学习函数、函数递归、练习)-CSDN博客 ============================================

    2024年02月04日
    浏览(27)
  • 网络安全入门学习练手——windows创建隐藏用户

    window 7 net user test$ 123456 /add net localgroup administrators test$ /add net users 没有发现该隐藏账户 这里可发现所有的用户和对应用户参数 登录进去后,对外显示的的是复制的Administrator账户 !注意: 但是上述的方法在注册表中仍然可以查看到(容易被杀毒软件查杀,且注册表可见用户名

    2024年02月09日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包