做商城网站在哪里注册营业执照/企业网站设计毕业论文

做商城网站在哪里注册营业执照,企业网站设计毕业论文,厦门网站建设哪家公司好,深圳营销网站建设公司《TCP/IP网络编程》学习笔记 | Chapter 19:Windows 平台下线程的使用 《TCP/IP网络编程》学习笔记 | Chapter 19:Windows 平台下线程的使用内核对象内核对象的定义内核对象归操作系统所有 基于 Windows 的线程创建进程与线程的关系Windows 中线程的创建方…

《TCP/IP网络编程》学习笔记 | Chapter 19:Windows 平台下线程的使用

  • 《TCP/IP网络编程》学习笔记 | Chapter 19:Windows 平台下线程的使用
    • 内核对象
      • 内核对象的定义
      • 内核对象归操作系统所有
    • 基于 Windows 的线程创建
      • 进程与线程的关系
      • Windows 中线程的创建方法
      • Windows 线程的销毁时间点
      • 编写多线程程序的环境设置
      • 创建“使用线程安全标准 C 函数”的线程
      • 句柄、内核对象和 ID 间的关系
    • 内核对象的 2 种状态
      • 内核对象状态及状态查看
      • 验证内核对象状态的 2 个函数
    • 习题
      • (1)下列关于内核对象的说法错误的是?
      • (2)现代操作系统大部分都在操作系统级别支持线程。根据该情况判断下列描述中错误的是?
      • (3)请比较从内存中完全销毁 Windows 线程和 Linux 线程的方法。
      • (4)通过线程创建过程解释内核对象、线程、句柄之间的关系。
      • (5)判断下列关于内核对象描述的正误。
      • (6)请解释“auto-reset模式”和manual-reset模式”的内核对象。区分二者的内核对象特征是什么?

《TCP/IP网络编程》学习笔记 | Chapter 19:Windows 平台下线程的使用

内核对象

要想掌握 Windows 平台下的线程,应首先理解内核对象(Kernel Objects)的概念。

内核对象的定义

操作系统创建的资源有很多种,如进程、线程、文件及即将介绍的信号量、互斥量等。其中大部分都是通过程序员的请求创建的,而且请求方式各不相同。虽然存在一些差异,但它们之间也有如下共同点:都是由 Windows 操作系统创建并管理的资源。

不同资源类型在管理方式也有差异。例如,文件管理中应注册并更新文件相关的数据I/O位置、文件的打开模式(rcad or write)等。如果是线程,则应注册并维护线程ID、线程所属进程等信息。操作系统为了以记录相关信息的方式管理各种资源,在其内部生成数据块(结构体变量)。当然,每种资源需要维护的信息不同,所以每种资源拥有的数据块格式也有差异。这类数据块称为“内核对象”。

假设在 Windows 下创建了 mydata.txt 文件,此时 Windows 操作系统将生成 1 个数据块以便管理,该数据块就是内核对象。同理,Windows 在创建进程、线程、线程同步信号量时也会生成相应的内核对象,用于管理操作系统资源。

内核对象归操作系统所有

线程、文件等资源的创建请求均在进程内部完成,因此,很容易产生“此时创建的内核对象所有者就是进程”的错觉。其实,内核对象所有者是内核(操作系统),内核对象的创建、管理、销毁时机的决定等工作均由操作系统完成。

基于 Windows 的线程创建

进程与线程的关系

现代操作系统都支持线程,因此,非显式创建线程的程序可描述为“单一线程模型的应用程序”,显式创建单独线程的程序可描述为“多线程模型的应用程序”。这就意味着 main 函数的运行同样基于线程完成,此时进程可以比喻为装有线程的篮子,实际的运行主体是线程。

Windows 中线程的创建方法

#include <windows.h>HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId
);

参数:

  • IpThreadAttributes:线程安全相关信息,使用默认设置时传递 NULL。
  • dwStackSize:要分配给线程的栈大小,传递 0 时生成默认大小的栈。
  • IpStartAddress:传递线程的 main 函数信息。
  • lpParameter:调用 main 函数时传递的参数信息。
  • dwCreationFlags:用于指定线程创建后的行为,传递 0 时,线程创建后立即进入可执行状态。
  • IpThreadld:用于保存线程 ID 的变量地址值。

成功时返回线程句柄,失败时返回 NULL。

调用该函数将创建线程,操作系统为了管理这些资源也将同时创建内核对象。最后返回用于区分内核对象的整数型“句柄”(Handle)。

第 1 章已介绍过,句柄相当于 Linux的文件描述符。

上述定义看起来有些复杂,其实只需要考虑 IpStartAddress 和 lpParameter 这 2 个参数,剩下的只需传递 0 或 NULL 即可。

Windows 线程的销毁时间点

Windows 线程在首次调用的线程 main 函数返回时销毁(销毁时间点和销毁方法与 Linux 不同)。

还有其他方法可以终止线程,但最好的方法就是让线程main函数终止(返回)。

编写多线程程序的环境设置

旧的 VC++6.0版默认只包含支持单线程的库,需要自行配置。

在项目的属性-代码生成界面,可以检查运行库:

在这里插入图片描述

创建“使用线程安全标准 C 函数”的线程

通过 CreateThread 函数调用创建出的线程在使用 C/C++ 标准函数时并不稳定。

如果线程要调用 C/C++ 标准函数,需要通过如下方法创建线程:

#include <process.h>unitptr_t _beginthreadex(void *security,unsigned stack_size,unsigned (*start_address)(void *),void *arglist,unsigned initflag,unsigned *thrdaddr
);

上述函数与之前的 CreateThread 函数相比,参数个数及各参数的含义和顺序的相同,只是变量名和参数类型有所不同。因此,用上述函数替换 CreateThread 函数时,只需适当更改数据类型。上述函数的返回值类型 uintptr_t 是 64 位 unsigned 整数型。

程序示例:

在这里插入代码片

运行结果:

在这里插入图片描述

与 Linux 相同,Windows 同样在 main 函数返回后终止进程,也同时终止其中包含的所有线程。另外,如果对上述代码进行运行的话,最后输出的内容并非字符串"end of main",而是"running thread"。但这是在 main 函数返回后,完全销毁进程前输出的字符串。

句柄、内核对象和 ID 间的关系

线程属于操作系统管理资源,伴随内核对象的创建,为了引用内核对象而返回句柄。

可以通过句柄区分内核对象,通过内核对象可以区分线程,最终,线程句柄成为区分线程的工具。

句柄的整数值在不同进程中可能重复。通过 CreateThread/_beginthreadex 函数可以得到线程 ID,它用于区分操作系统创建的所有线程,在跨进程范围内不会重复。

内核对象的 2 种状态

应用程序实现过程中需要特别关注的信息被赋予某种“状态”。

线程终止状态又称 signaled 状态,未终止状态称为 non-signaled 状态。

内核对象状态及状态查看

进程或线程终止时,操作系统会把相应的内核对象改为 signaled 状态。

这也意味着,进程和线程的内核对象初始状态是 non-signaled 状态。

内核对象带有 1 个 boolean 变量,其初始值为 FALSE,此时的状态就是 non-signaled 状态。如果发生约定的情况,把该变量改为 TRUE,此时的状态就是 signaled 状态。内核对象类型不同,进入 signaled 状态的情况也有所区别(即对应事件也有区别)。

验证内核对象状态的 2 个函数

首先介绍 WaitForSingleObject 函数,该函数针对单个内核对象验证 signaled 状态。

#include<windows.h>DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds
);

参数:

  • hHandle:查看状态的内核对象句柄。
  • dwMilliseconds:以 1ms 为单位指定超时,传递 INFINITE 时函数不会返回,直到内核对象变成 signaled状态。

进入 signaled 状态返回 WAIT_OBJECT_0,超时返回 WAIT_TIMEOUT,失败时返回 WAIT_FAILED。

该函数由于发生事件(变为 signaled 状态)返回时,有时会把相应内核对象再次改为 non-signaled 状态。这种可以再次进入 non-signaled 状态的内核对象称为“auto-reset模式”的内核对象,而不会自动跳转到 non-signaled 状态的内核对象称为“manual-reset模式”的内核对象。

WaitForMultipleObjects 函数与 WaitForSingleObject 函数不同,可以验证多个内核对象状态。

#include <windows.h>DWORD WaitForMultipleObjects(DWORD nCount,const HANDLE *lphHandles,BOOL bWaitAll,DWORD dwMilliseconds
);

参数:

  • nCount:需验证的内核对象数。
  • IpHandles:存有内核对象句柄的数组地址值。
  • bWaitAll:如果为 TRUE,则所有内核对象全部变为 signaled 时返回;如果为 FALSE,则只要有 1 个对象的状态变为 signaled 就会返回。
  • dwMilliseconds:以 1ms 为单指定超时,传递 INFINITE 时函数不会返回,直到内核对象变为 signaled 状态。

成功时返回事件信息,失败时返回 WAIT_FAILED。

下面利用 WaitForSingleObject 函数尝试解决示例的问题。

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <process.h>unsigned WINAPI ThreadFunc(void *arg); // WINAPI 是 Windows 固有的关键字,表示遵守 _beginthreadex 函数的调用规定int main(int argc, char *argv[])
{HANDLE hThread;DWORD wr;unsigned threadID;int param = 5;hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (void *)&param, 0, &threadID);if (hThread == 0){puts("_beginthreadex() error");return -1;}if ((wr = WaitForSingleObject(hThread, INFINITE)) == WAIT_FAILED){puts("thread wait error");return -1;}printf("wait result: %s \n", (wr == WAIT_OBJECT_0) ? "signaled" : "time-out");puts("end of main");system("pause");return 0;
}unsigned WINAPI ThreadFunc(void *arg)
{int cnt = *((int *)arg);for (int i = 0; i < cnt; i++){Sleep(1000);puts("runnning thread");}return 0;
}

运行结果:

在这里插入图片描述

可以看出,thread1_win.c 中的问题得到解决。

第 18 章在 Linux 平台下分析了临界区问题,本章最后的内容将留给 Windows 平台下的临界区问题。

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <process.h>#define NUM_THREAD 50
unsigned WINAPI threadInc(void *arg);
unsigned WINAPI threadDes(void *arg);
long long num = 0;int main(int argc, char *argv[])
{HANDLE tHandles[NUM_THREAD];int i;printf("sizeof long long: %d \n", sizeof(long long));for (i = 0; i < NUM_THREAD; i++){if (i % 2)tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadInc, NULL, 0, NULL);elsetHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadDes, NULL, 0, NULL);}WaitForMultipleObjects(NUM_THREAD, tHandles, TRUE, INFINITE);printf("result: %lld \n", num);system("pause");return 0;
}unsigned WINAPI threadInc(void *arg)
{int i;for (i = 0; i < 50000000; i++)num += 1;return 0;
}unsigned WINAPI threadDes(void *arg)
{int i;for (i = 0; i < 50000000; i++)num -= 1;return 0;
}

运行结果:

在这里插入图片描述

即使多运行几次也无法得到正确结果,而且每次结果都不同。可以利用第 20 章的同步技术得到预想的结果。

习题

(1)下列关于内核对象的说法错误的是?

a. 内核对象是操作系统保存各种资源信息的数据块。
b. 内核对象的所有者是创建该内核对象的进程。
c. 由用户进程创建并管理内核对象。
d. 无论操作系统创建和管理的资源类型是什么,内核对象的数据块结构都完全相同。

答:

b、c、d。

(2)现代操作系统大部分都在操作系统级别支持线程。根据该情况判断下列描述中错误的是?

a. 调用 main 函数的也是线程。
b. 如果进程不创建线程,则进程内不存在任何线程。
c. 多线程模型是进程内可以创建额外线程的程序类型。
d. 单一线程模型是进程内只额外创建 1 个线程的程序模型。

答:

b、d。

(3)请比较从内存中完全销毁 Windows 线程和 Linux 线程的方法。

在这里插入图片描述

(4)通过线程创建过程解释内核对象、线程、句柄之间的关系。

线程创建过程:

  1. 用户程序通过系统调用请求创建线程。
  2. 内核创建线程对象。
  3. 内核将线程对象的引用封装为句柄,返回给用户程序。
  4. 线程开始执行用户定义的 main 函数,代码运行在用户态。
  5. 当线程函数结束且所有句柄关闭,内核销毁线程对象。

在这里插入图片描述

总结:

内核对象是操作系统的核心资源管理者,线程是用户程序与内核协作的执行单元,句柄是用户程序安全访问内核对象的桥梁。三者通过线程创建过程紧密协作,确保资源的隔离性、安全性和高效管理。

(5)判断下列关于内核对象描述的正误。

  • 内核对象只有 signaled 和 non- signaled 这 2 种状态。(×)
  • 内核对象需要转为 signaled 状态时,需要程序员亲自将内核对象的状态改为 signaled 状态。(×)
  • 线程的内核对象在线程运行时处于 sigaled 状态,线程终止则进入 non-signaled 状态。(×)

(6)请解释“auto-reset模式”和manual-reset模式”的内核对象。区分二者的内核对象特征是什么?

auto-reset 模式:当事件被触发,只有一个等待线程会被唤醒,随后事件自动重置为 non-signaled 状态。如果有多个线程在等待,只有一个线程能继续执行,其余线程继续等待。

manual-reset 模式:当事件被触发,所有等待线程都会被唤醒,事件保持 signaled 状态,直到手动重置为 non- signaled 状态。

选择哪种模式取决于具体需求:是唤醒单个线程还是多个线程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/72792.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker需要sudo才能使用

一种方法是添加当前用户到docker组里去&#xff0c;当时添加的时候貌似是没问题的&#xff0c;但是现在又不可以了 产生的报错 ❯ docker images Cannot connect to the Docker daemon at unix:///home/ying/.docker/desktop/docker.sock. Is the docker daemon running?解决…

学习记录 6 pointnet复现

一、复现代码 然后去找相关的2d的声呐图像分类的算法 融合可以搞的&#xff0c;虽然有文献但是不多&#xff0c;感觉也是可以的 """ Author: Benny Date: Nov 2019 """import os import sys import torch import numpy as npimport datetime …

Linux 文件操作-标准IO函数3- fread读取、fwrite写入、 fprintf向文件写入格式化数据、fscanf逐行读取格式化数据的验证

目录 1. fread 从文件中读取数据 1.1 读取次数 每次读取字节数 < 原内容字节数 1.2 读取次数 每次读取字节数 > 原内容字节数 2.fwrite 向文件中写入数据 2.1写入字符串验证 2.2写入结构体验证 3. fprintf 将数据写入到指定文件 4. fscanf 从文件中逐行读取内容…

Python 中下划线 “_” 的多面性:从变量到约定

# Python中下划线“_”的多面性&#xff1a;从变量到约定 在Python的语法体系里&#xff0c;下划线“_”看似毫不起眼&#xff0c;实则扮演着极为重要且多样化的角色。它不仅能作为普通变量参与编程&#xff0c;更在多个特殊场景下有着独特的用途与约定。深入理解下划线的各种…

深入 Linux 声卡驱动开发:核心问题与实战解析

1. 字符设备驱动如何为声卡提供操作接口&#xff1f; 问题背景 在 Linux 系统中&#xff0c;声卡被抽象为字符设备。如何通过代码让应用程序能够访问声卡的录音和播放功能&#xff1f; 核心答案 1.1 字符设备驱动的核心结构 Linux 字符设备驱动通过 file_operations 结构体定…

基于Spring Boot的图书管理系统的设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

STM32HAL库,解决串口UART中断接收到的第一个字节数据丢失

1.问题描述&#xff1a; 只有上电后第一次接收到的第一字节数据会丢失&#xff0c;往后再接收也不会存在问题了。 2.先贴出来重写UART中断回调函数 我在接收到第一字节数据后开启定时器中断的&#xff0c;做一个超时处理&#xff0c;每次接收到数据会对定时器计数值清零&…

解决 vxe-table 固定列对不齐,滚动后错位、展开行遮挡的问题,解决渲染空白、边框丢失问题

解决 vxe-table 固定列对不齐&#xff0c;滚动后错位、展开行遮挡的问题&#xff0c;解决渲染空白、边框丢失问题。 解决方法&#xff0c;更新到最新版本就完美解决了&#xff1b;v4 版本更新到 v4.12&#xff0c;v3版本更新到 v3.14 查看官网&#xff1a;https://vxetable.cn…

设备健康管理系统是什么,设备健康管理系统多少钱?

想象一下&#xff0c;你的汽车在仪表盘报警前 3 天&#xff0c;手机就收到 “发动机轴承剩余寿命 1500 公里” 的提醒 —— 这就是 ** 设备健康管理系统&#xff08;EHM&#xff09;** 的日常。在制造业&#xff0c;设备故障每年造成全球 3.4 万亿美元损失&#xff0c;而 80% 的…

区块链(Blockchain)

区块链&#xff08;Blockchain&#xff09;是一种去中心化、分布式的账本技术&#xff0c;它通过密码学保证数据的安全性和不可篡改性。它的核心特点包括去中心化、不可篡改性、可追溯性、智能合约等。 区块链的关键概念 区块&#xff08;Block&#xff09;&#xff1a;每个区…

和鲸科技受邀赴中国气象局气象干部培训学院湖南分院开展 DeepSeek 趋势下的人工智能技术应用专题培训

为深入贯彻落实国家关于人工智能与气象业务深度融合的战略部署&#xff0c;提升在实际业务中应用人工智能技术解决问题的能力&#xff0c;推动气象现代化高质量发展&#xff0c;中国气象局气象干部培训学院湖南分院于 2025 年 3 月 14 日组织开展 “DeepSeek 等人工智能技术在气…

Ubuntu 24 常用命令方法

文章目录 环境说明1、账号管理1.1、启用 root 2、包管理工具 apt & dpkg2.1、apt 简介 & 阿里源配置2.2、dpkg 简介2.3、apt 和 dpkg 两者之间的关系2.4、常用命令 3、启用 ssh 服务4、防火墙5、开启远程登录6、关闭交换分区7、build-essential&#xff08;编译和开发软…

OpenCV计算摄影学(22)将输入的彩色图像转换为两种风格的铅笔素描效果函数pencilSketch()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 铅笔风格非写实线描图。 该函数通过图像处理技术将输入的彩色图像转换为两种风格的铅笔素描效果&#xff1a; dst1&#xff1a;炭笔效果的灰度图…

hackmyvm-Smol

信息收集 ┌──(root㉿kali)-[/home/kali] └─# arp-scan -I eth1 192.168.56.0/24 Interface: eth1, type: EN10MB, MAC: 00:0c:29:34:da:f5, IPv4: 192.168.56.103 WARNING: Cannot open MAC/Vendor file ieee-oui.txt: Permission denied WARNING: Cannot open MAC/Vendo…

使用DeepSeek和墨刀AI,写PRD文档、画原型图的思路、过程及方法

使用DeepSeek和墨刀AI&#xff0c;写PRD文档、画原型图的思路、过程及方法 现在PRD文档要如何写更高效、更清晰、更完整&#xff1f; 还是按以前的思路写PRD&#xff0c;就还是以前的样子。 现在AI这么强大&#xff0c;产品经理如何使用DeepSeek写PRD文档&#xff0c;产品经…

SpringData Redis缓存:自定义序列化与过期策略

文章目录 引言一、Spring Cache与Redis集成基础二、Redis缓存配置基础三、自定义序列化策略四、实现自定义序列化器五、多级缓存配置六、自定义过期策略七、缓存注解的高级应用八、实现缓存预热与更新策略九、缓存监控与统计总结 引言 在现代高并发分布式系统中&#xff0c;缓…

HOVER:人形机器人的多功能神经网络全身控制器

编辑&#xff1a;陈萍萍的公主一点人工一点智能 HOVER&#xff1a;人形机器人的多功能神经网络全身控制器HOVER通过策略蒸馏和统一命令空间设计&#xff0c;为人形机器人提供了通用、高效的全身控制框架。https://mp.weixin.qq.com/s/R1cw47I4BOi2UfF_m-KzWg 01 介绍 1.1 摘…

mybatis_plus的乐观锁

乐观锁&#xff1a;总是假设最好的情况&#xff0c;每次读取数据时认为数据不会被修改&#xff08;即不加锁&#xff09;&#xff0c;当进行更新操作时&#xff0c;会判断这条数据是否被修改&#xff0c;未被修改&#xff0c;则进行更新操作。若被修改&#xff0c;则数据更新失…

AT指令集-NBIOT

是什么&#xff1f; 窄带物联网&#xff08;Narrow Band Internet of Things, NB-IoT&#xff09;成为万物互联网络的一个重要分支支持低功耗设备在广域网的蜂窝数据连接&#xff0c;也被叫作低功耗广域网(LPWAN)NB-IoT支持待机时间长、对网络连接要求较高设备的高效连接NB-Io…

CBNet:一种用于目标检测的复合骨干网架构之论文阅读

摘要 现代顶级性能的目标检测器在很大程度上依赖于骨干网络&#xff0c;而骨干网络的进步通过探索更高效的网络结构带来了持续的性能提升。本文提出了一种新颖且灵活的骨干框架——CBNet&#xff0c;该框架利用现有的开源预训练骨干网络&#xff0c;在预训练-微调范式下构建高…