Linux和windows进程同步与线程同步那些事儿(四):windows 下进程同步
Linux和windows进程同步与线程同步那些事儿(一)
Linux和windows进程同步与线程同步那些事儿(二): windows线程同步详解示例
Linux和windows进程同步与线程同步那些事儿(三): Linux线程同步详解示例
Linux和windows进程同步与线程同步那些事儿(四):windows 下进程同步
Linux和windows进程同步与线程同步那些事儿(五):Linux下进程同步
1. 互斥量(Mutex):
互斥量是最常用的线程同步机制,它可以确保在同一时间只有一个线程可以访问共享资源。
在Windows中,可以使用CreateMutex
函数来创建互斥量。
下面是一个使用互斥量实现进程同步的代码示例。该示例展示了两个进程之间如何使用互斥量来保证共享资源的互斥访问。
#include <iostream>
#include <windows.h>int main() {// 创建互斥量对象HANDLE hMutex = CreateMutex(NULL, FALSE, "MyMutex");if (hMutex == NULL) {std::cout << "互斥量创建失败!" << std::endl;return 1;}// 尝试获取互斥量的所有权DWORD dwWaitResult = WaitForSingleObject(hMutex, INFINITE);if (dwWaitResult == WAIT_OBJECT_0) {std::cout << "进程A获得了互斥量的所有权!" << std::endl;// 模拟共享资源的访问std::cout << "进程A正在访问共享资源..." << std::endl;Sleep(5000);// 释放互斥量的所有权ReleaseMutex(hMutex);std::cout << "进程A释放了互斥量的所有权!" << std::endl;}else {std::cout << "进程A无法获取互斥量的所有权!" << std::endl;}// 关闭互斥量句柄CloseHandle(hMutex);return 0;
}
#include <iostream>
#include <windows.h>int main() {// 创建互斥量对象HANDLE hMutex = CreateMutex(NULL, FALSE, "MyMutex");if (hMutex == NULL) {std::cout << "互斥量创建失败!" << std::endl;return 1;}// 尝试获取互斥量的所有权DWORD dwWaitResult = WaitForSingleObject(hMutex, INFINITE);if (dwWaitResult == WAIT_OBJECT_0) {std::cout << "进程B获得了互斥量的所有权!" << std::endl;// 模拟共享资源的访问std::cout << "进程B正在访问共享资源..." << std::endl;Sleep(3000);// 释放互斥量的所有权ReleaseMutex(hMutex);std::cout << "进程B释放了互斥量的所有权!" << std::endl;}else {std::cout << "进程B无法获取互斥量的所有权!" << std::endl;}// 关闭互斥量句柄CloseHandle(hMutex);return 0;
}
在上面的代码示例中,进程A和进程B都通过调用CreateMutex
函数来创建了一个名为"MyMutex"的互斥量对象。接着,它们分别调用WaitForSingleObject
函数来尝试获取互斥量的所有权。
如果某个进程成功获取了互斥量的所有权(即dwWaitResult
的值为WAIT_OBJECT_0
),那么它就可以访问共享资源。在示例中,为了模拟共享资源的访问,我们使用了Sleep
函数来暂停程序的执行。
完成对共享资源的访问后,进程需要调用ReleaseMutex
函数来释放互斥量的所有权,以便其他进程可以获取互斥量的所有权。
最后,进程要调用CloseHandle
函数来关闭互斥量句柄,释放系统资源。
请注意,这只是一个简单的示例,实际的应用中可能还需要处理异常情况、错误处理等。
2. 事件(Event):
事件用于线程间的通信和同步,允许线程等待某个特定事件的发生。
在Windows中,可以使用CreateEvent
函数来创建事件对象。
下面是一个使用事件(Event)实现进程同步的代码示例。该示例展示了两个进程之间如何使用事件来进行进程同步。
#include <iostream>
#include <windows.h>int main() {// 创建事件对象HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, "MyEvent");if (hEvent == NULL) {std::cout << "事件创建失败!" << std::endl;return 1;}// 等待事件变为有信号状态DWORD dwWaitResult = WaitForSingleObject(hEvent, INFINITE);if (dwWaitResult == WAIT_OBJECT_0) {std::cout << "进程A检测到事件有信号!" << std::endl;// 执行需要同步的操作std::cout << "进程A正在执行同步操作..." << std::endl;Sleep(5000);std::cout << "进程A完成同步操作!" << std::endl;}else {std::cout << "进程A等待事件超时或发生其他错误!" << std::endl;}// 关闭事件句柄CloseHandle(hEvent);return 0;
}
#include <iostream>
#include <windows.h>int main() {// 打开事件对象HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, "MyEvent");if (hEvent == NULL) {std::cout << "事件打开失败!" << std::endl;return 1;}// 设置事件为有信号状态if (SetEvent(hEvent)) {std::cout << "进程B设置了事件的信号!" << std::endl;}else {std::cout << "进程B设置事件的信号失败!" << std::endl;}// 关闭事件句柄CloseHandle(hEvent);return 0;
}
在上面的代码示例中,进程A通过调用CreateEvent
函数来创建了一个名为"MyEvent"的事件对象。而进程B则通过调用OpenEvent
函数来打开同一个事件对象。
进程A调用WaitForSingleObject
函数来等待事件变为有信号状态。一旦事件有信号,进程A就可以执行需要同步的操作。在示例中,我们使用了Sleep
函数来模拟同步操作的执行。
进程B在需要进行同步的时候,调用SetEvent
函数来设置事件的信号。这样,进程A就会被唤醒,继续执行同步操作。
请注意,事件对象具有自动复位(auto-reset)的特性,即一旦某个等待事件的进程被唤醒,事件会自动重置为无信号状态,其他等待事件的进程将继续等待。
最后,进程要调用CloseHandle
函数来关闭事件句柄,释放系统资源。
3. 临界区(Critical Section):
临界区用于保护共享资源,确保在同一时间只有一个线程可以访问。
在Windows中,可以使用InitializeCriticalSection
函数来初始化临界区。
下面是一个使用临界区(Critical Section)实现进程同步的代码示例。该示例展示了两个进程之间如何使用临界区来进行进程同步。
#include <iostream>
#include <windows.h>CRITICAL_SECTION g_cs; // 全局临界区对象int main() {// 初始化临界区InitializeCriticalSection(&g_cs);// 进入临界区EnterCriticalSection(&g_cs);std::cout << "进程A进入临界区,执行同步操作..." << std::endl;Sleep(5000); // 模拟同步操作std::cout << "进程A完成同步操作,退出临界区!" << std::endl;// 离开临界区LeaveCriticalSection(&g_cs);// 销毁临界区DeleteCriticalSection(&g_cs);return 0;
}
#include <iostream>
#include <windows.h>CRITICAL_SECTION g_cs; // 全局临界区对象int main() {// 初始化临界区InitializeCriticalSection(&g_cs);// 进入临界区EnterCriticalSection(&g_cs);std::cout << "进程B进入临界区,执行同步操作..." << std::endl;Sleep(5000); // 模拟同步操作std::cout << "进程B完成同步操作,退出临界区!" << std::endl;// 离开临界区LeaveCriticalSection(&g_cs);// 销毁临界区DeleteCriticalSection(&g_cs);return 0;
}
在上面的代码示例中,我们使用CRITICAL_SECTION
类型的全局变量g_cs
作为临界区对象。
进程A和进程B都会初始化临界区对象,进入临界区进行同步操作。
在示例中,我们使用了Sleep
函数来模拟同步操作的执行。
进程A和进程B在完成同步操作后,都需要离开临界区。
最后,进程要调用DeleteCriticalSection
函数来销毁临界区对象,释放系统资源。
请注意,临界区是进程内的同步机制,不适用于跨进程的同步。如果需要跨进程的同步,可以考虑使用互斥量(Mutex)或事件(Event)等其他机制。
4. 信号量(Semaphore):
信号量是一种经典的线程同步机制,它可以用于控制对共享资源的访问。
在Windows中,可以使用CreateSemaphore
函数来创建信号量。
下面是一个使用信号量(Semaphore)实现进程同步的代码示例。该示例展示了两个进程之间如何使用信号量来进行进程同步。
#include <iostream>
#include <windows.h>HANDLE g_semaphore; // 全局信号量句柄int main() {// 创建一个信号量,初始值为0,用于进程同步g_semaphore = CreateSemaphore(NULL, 0, 1, L"ProcessSync");std::cout << "进程A执行同步操作..." << std::endl;Sleep(5000); // 模拟同步操作std::cout << "进程A完成同步操作,释放信号量!" << std::endl;ReleaseSemaphore(g_semaphore, 1, NULL); // 释放信号量,允许进程B执行// 关闭信号量句柄CloseHandle(g_semaphore);return 0;
}
#include <iostream>
#include <windows.h>HANDLE g_semaphore; // 全局信号量句柄int main() {// 创建一个信号量,初始值为0,用于进程同步g_semaphore = CreateSemaphore(NULL, 0, 1, L"ProcessSync");// 进程B等待信号量,直到进程A释放信号量WaitForSingleObject(g_semaphore, INFINITE);std::cout << "进程B执行同步操作..." << std::endl;Sleep(5000); // 模拟同步操作std::cout << "进程B完成同步操作,释放信号量!" << std::endl;ReleaseSemaphore(g_semaphore, 1, NULL); // 释放信号量,允许其他进程执行// 关闭信号量句柄CloseHandle(g_semaphore);return 0;
}
在上面的示例代码中,我们使用了HANDLE
类型的全局变量g_semaphore
作为信号量句柄。
进程A创建了一个名为"ProcessSync"的信号量,并执行同步操作之后,调用ReleaseSemaphore
函数释放信号量。
进程B在等待信号量状态下,调用WaitForSingleObject
函数等待进程A释放信号量,然后执行同步操作。
最后,进程要调用CloseHandle
函数来关闭信号量句柄,释放系统资源。
请注意,信号量是一种用于进程间同步的机制,可以在不同进程之间实现同步。在示例中,我们使用了一个简单的二进制信号量,它的初始值为0,进程A通过ReleaseSemaphore
函数将其值设置为1,使进程B可以继续执行。
5. 命名管道(Named Pipe):
命名管道是一种进程间通信的机制,可以用于实现进程间的数据交换和同步。
在Windows中,可以使用CreateNamedPipe
函数来创建命名管道。
在 Windows 下,可以使用命名管道(Named Pipe)实现多进程间的同步。命名管道是一种特殊的文件,用于在不同进程间进行通信。下面是一个使用命名管道实现多进程同步的 C++ 代码示例:
进程A:写入数据
#include <iostream>
#include <windows.h>int main()
{HANDLE hPipe;// 创建命名管道LPCWSTR pipeName = TEXT("\\\\.\\pipe\\my_pipe");hPipe = CreateNamedPipe(pipeName,PIPE_ACCESS_DUPLEX,PIPE_TYPE_MESSAGE | PIPE_WAIT,1, // 最大实例数65536, // 输出缓冲区大小65536, // 输入缓冲区大小0, // 默认超时时间NULL // 安全属性);// 等待进程B连接ConnectNamedPipe(hPipe, NULL);// 向管道写入数据const char* data = "Hello, World!";DWORD bytesWritten;WriteFile(hPipe, data, strlen(data) + 1, &bytesWritten, NULL);// 关闭管道DisconnectNamedPipe(hPipe);CloseHandle(hPipe);return 0;
}
进程B:读取数据
#include <iostream>
#include <windows.h>int main()
{HANDLE hPipe;// 连接到命名管道LPCWSTR pipeName = TEXT("\\\\.\\pipe\\my_pipe");hPipe = CreateFile(pipeName,GENERIC_READ,0, // 共享模式NULL, // 安全属性OPEN_EXISTING,0, // 属性和标志NULL // 模板文件);// 从管道读取数据char buffer[65536];DWORD bytesRead;ReadFile(hPipe, buffer, sizeof(buffer), &bytesRead, NULL);// 打印数据std::cout << buffer << std::endl;// 关闭管道CloseHandle(hPipe);return 0;
}
上述代码中,进程A创建了一个命名管道,并等待进程B连接。然后,它向管道写入数据。进程B连接到同一个命名管道,并读取进程A写入的数据。
让我们更详细地解释一下代码:
-
在进程A中,
CreateNamedPipe
函数用于创建命名管道。参数pipeName
指定了命名管道的名称,格式为\\.\pipe\pipeName
。其他参数设置了管道的访问权限、缓冲区大小等。 -
进程A调用
ConnectNamedPipe
函数等待进程B连接。 -
进程A使用
WriteFile
函数向管道写入数据。 -
进程B使用
CreateFile
函数连接到命名管道。 -
进程B调用
ReadFile
函数从管道中读取数据。 -
最后,进程B关闭了管道。
在实际使用中,可以根据需要对代码进行修改和扩展,以满足你的具体需求。例如,你可以使用多线程创建多个进程,或者通过命名管道进行双向通信。
6. 共享内存(Shared Memory):
共享内存允许多个进程访问同一块内存区域,从而实现进程间的数据共享和通信。
在Windows中,可以使用CreateFileMapping
和MapViewOfFile
等函数来创建和访问共享内存区域。
下面是一个使用共享内存在Windows下实现多个进程同步的代码示例:
#include <iostream>
#include <Windows.h>// 共享内存结构体
struct SharedData {HANDLE mutex; // 互斥量HANDLE event; // 事件CONDITION_VARIABLE conditionVariable; // 条件变量int counter; // 共享计数器
};int main() {// 创建共享内存HANDLE hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE,nullptr,PAGE_READWRITE,0,sizeof(SharedData),L"MySharedMemory");if (hMapFile == NULL) {std::cerr << "Failed to create shared memory" << std::endl;return 1;}// 获取共享内存指针SharedData* sharedData = (SharedData*)MapViewOfFile(hMapFile,FILE_MAP_ALL_ACCESS,0,0,sizeof(SharedData));if (sharedData == NULL) {std::cerr << "Failed to map shared memory" << std::endl;CloseHandle(hMapFile);return 1;}// 初始化互斥量、事件和条件变量sharedData->mutex = CreateMutex(nullptr, FALSE, nullptr);sharedData->event = CreateEvent(nullptr, FALSE, FALSE, nullptr);InitializeConditionVariable(&sharedData->conditionVariable);sharedData->counter = 0;// 创建多个进程进行同步操作for (int i = 0; i < 5; i++) {STARTUPINFO si = {};PROCESS_INFORMATION pi = {};wchar_t cmdLine[] = L"ChildProcess.exe"; // 子进程程序名// 启动子进程if (!CreateProcess(nullptr,cmdLine,nullptr,nullptr,FALSE,0,nullptr,nullptr,&si,&pi)) {std::cerr << "Failed to create child process" << std::endl;CloseHandle(hMapFile);return 1;}// 关闭子进程句柄CloseHandle(pi.hThread);CloseHandle(pi.hProcess);}// 等待所有子进程执行完毕WaitForMultipleObjects(5, sharedData->processHandles, TRUE, INFINITE);// 输出计数器值std::cout << "Counter = " << sharedData->counter << std::endl;// 释放资源UnmapViewOfFile(sharedData);CloseHandle(sharedData->mutex);CloseHandle(sharedData->event);CloseHandle(hMapFile);return 0;
}
这个示例中,首先创建了一个共享内存来存储互斥量、事件和条件变量等同步对象以及一个共享计数器。然后创建了多个子进程,在子进程中进行同步操作。
子进程代码示例(ChildProcess.exe):
#include <iostream>
#include <Windows.h>struct SharedData {HANDLE mutex;HANDLE event;CONDITION_VARIABLE conditionVariable;int counter;
};int main() {HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS,FALSE,L"MySharedMemory");if (hMapFile == NULL) {std::cerr << "Failed to open shared memory" << std::endl;return 1;}SharedData* sharedData = (SharedData*)MapViewOfFile(hMapFile,FILE_MAP_ALL_ACCESS,0,0,sizeof(SharedData));if (sharedData == NULL) {std::cerr << "Failed to map shared memory" << std::endl;CloseHandle(hMapFile);return 1;}// 等待主进程通知WaitForSingleObject(sharedData->event, INFINITE);// 互斥量保护临界区WaitForSingleObject(sharedData->mutex, INFINITE);// 执行同步操作sharedData->counter++;std::cout << "Child process counter = " << sharedData->counter << std::endl;// 离开临界区ReleaseMutex(sharedData->mutex);// 通知主进程完成WakeConditionVariable(&sharedData->conditionVariable);// 释放资源UnmapViewOfFile(sharedData);CloseHandle(hMapFile);return 0;
}
在子进程中,首先打开共享内存,并获取共享内存指针。然后等待主进程通知,获取互斥量保护临界区,执行同步操作,离开临界区,通知主进程完成,并释放资源。
总结
互斥量(mutex):
适用场景:多个进程需要争夺同一个资源时,只能有一个进程访问资源。
优点:简单易用,能够实现多个进程间的互斥访问。
缺点:性能较低,需要进行系统调用,可能引起上下文切换开销。
事件(event):
适用场景:多个进程需要等待某个特定事件的发生后才能继续执行。
优点:可以在多个进程之间进行高效的同步。
缺点:只能用于单个事件的同步,不能用于争夺资源的同步。
临界区(critical section):
适用场景:多个进程需要访问共享资源时,只能有一个进程访问资源。
优点:具有较高的性能,适用于保护共享资源的场景。
缺点:只能用于同一个进程内的进程同步,不能用于跨进程同步。
信号量(semaphore):
适用场景:多个进程需要访问有限数量的资源时,控制同时访问的进程数量。
优点:可以用于控制同时访问资源的进程数量。
缺点:较复杂,容易引发死锁问题。
命名管道(named pipe):
适用场景:多个进程之间进行双向通信和同步。
优点:提供了进程间的可靠通信和同步机制。
缺点:性能较低,只能用于进程之间的通信和同步。
共享内存(shared memory):
适用场景:多个进程需要共享大块数据时。
优点:高效的进程间通信,能够实现数据共享。
缺点:需要进行同步,容易引发数据不一致或竞态条件。
综合比较:
- 互斥量 : 适用于争夺单个资源的情况,使用简单,但性能较低。
- 事件 : 适用于等待特定事件发生后才能继续执行的场景,同步效率高。
- 临界区: 适用于保护共享资源的场景,性能较高。
- 信号量: 适用于控制同时访问资源的进程数量,但使用较复杂,容易产生死锁。
- 命名管道: 适用于进程间的通信和同步,但性能较低。
- 共享内存: 适用于共享大块数据的场景,需要进行同步操作,可能引发竞态条件。
根据具体的场景和需求,可以选择合适的进程同步机制来实现进程间的同步和通信。
相关文章:
Linux和windows进程同步与线程同步那些事儿(四):windows 下进程同步
Linux和windows进程同步与线程同步那些事儿(一) Linux和windows进程同步与线程同步那些事儿(二): windows线程同步详解示例 Linux和windows进程同步与线程同步那些事儿(三): Linux线…...
1. Logback介绍
Logback介绍 Logback旨在成为流行的log4j项目的继任者。它由Ceki Glc设计,他是log4j的创始人。它基于十年在设计工业级日志系统方 面的经验。结果产品,即logback,比所有现有的日志系统更快,具有更小的占用空间,有时差距…...

SqueezeNet:通过紧凑架构彻底改变深度学习
一、介绍 在深度学习领域,对效率和性能的追求往往会带来创新的架构。SqueezeNet 是神经网络设计的一项突破,体现了这种追求。本文深入研究了 SqueezeNet 的复杂性,探讨其独特的架构、设计背后的基本原理、应用及其对深度学习领域的影响。 在创…...
Python:正则表达式之re.group()用法
Python正则表达式之re.group()用法学习笔记 正则表达式是在处理字符串时非常有用的工具,而re.group()是在匹配到的文本中提取特定分组内容的方法之一。 1. re.group()的基本用法 在正则表达式中,通过圆括号可以创建一个或多个分组。re.group()用于获取…...

Shiro框架:Shiro登录认证流程源码解析
目录 1.用户登录认证流程 1.1 生成认证Token 1.2 用户登录认证 1.2.1 SecurityManager login流程解析 1.2.1.1 authenticate方法进行登录认证 1.2.1.1.1 单Realm认证 1.2.1.2 认证通过后创建登录用户对象 1.2.1.2.1 复制SubjectContext 1.2.1.2.2 对subjectContext设…...

WEB前端人机交互导论实验-实训2格式化文本、段落与列表
1.项目1 文本与段落标记的应用: A.题目要求: B.思路: (1)首先,HTML文档的基本结构是通过<html>...</html>标签包围的,包含了头部信息和页面主体内容。 (2)在头部信息…...
Python:list列表与tuple元组的区别
在Python中,List(列表) 和Tuple(元组) 都是用于存储一组有序元素的数据结构,但它们有一些关键的区别,包括可变性、性能、语法等方面。 1. List(列表) 用法:…...

如何基于 Gin 封装出属于自己 Web 框架?
思路 在基于 Gin 封装出属于自己的 Web 框架前,你需要先了解 Gin 的基本用法和设计理念。 然后,你可以通过以下步骤来封装自己的 Web 框架: 封装路由:Gin 的路由是通过 HTTP 方法和 URL 路径进行匹配的,你可以根据自己…...

VUE element-ui实现表格动态展示、动态删减列、动态排序、动态搜索条件配置、表单组件化。
1、实现效果 1.1、文件目录 1.2、说明 1、本组件支持列表的表头自定义配置,checkbox实现 2、本组件支持列表列排序,vuedraggable是拖拽插件,上图中字段管理里的拖拽效果 ,需要的话请自行npm install 3、本组件支持查询条件动态…...

压测工具ab
Apache Benchmark(简称ab) 是Apache安装包中自带的压力测试工具 ,简单易用, Apache的ab命令模拟多线程并发请求,测试服务器负载压力,也可以适用于其他服务:nginx、lighthttp、tomcat、IIS等其它Web服务器的压力 采用平台…...

P4学习(一) 环境搭建
系列文章目录 第一章 P4学习入门之虚拟机环境搭建 文章目录 系列文章目录前言一、P4是什么?二、搭建步骤1.下载虚拟机镜像2.虚拟机管理软件载入镜像2.1 找到你镜像的所在位置2.2 打开VMware Workstation2.3 载入镜像 3.检验环境是否配置成功 P4 的真机环境搭建 前言…...

openssl3.2 - 官方demo学习 - server-arg.c
文章目录 openssl3.2 - 官方demo学习 - server-arg.c概述笔记备注END openssl3.2 - 官方demo学习 - server-arg.c 概述 TLS服务器, 等客户端来连接; 如果客户端断开了, 通过释放bio来释放客户端socket, 然后继续通过bio读来aceept. 笔记 对于开源工程, 不可能有作者那么熟悉…...

Windows RPC运行时漏洞事后总结
2022年4月前后,Windows RPC运行时被曝出存在远程代码执行漏洞,当时曾引起很多人广泛关注。微软很快做出反应,发布补丁程序进行修补。这次事件中,Windows远程过程调用(RPC)运行时共出现三个关键漏洞…...

运算电路(1)——加法器
一、引言 微处理器是由一片或少数几片大规模集成电路组成的中央处理器。这些电路执行控制部件和算术逻辑部件的功能。微处理器能完成取指令、执行指令,以及与外界存储器和逻辑部件交换信息等操作,是微型计算机的运算控制部分。它可与存储器和外围电路芯片…...
ESP32-WIFI(Arduino)
ESP32-WIFI Wi-Fi是一种基于IEEE 802.11标准的无线局域网技术,是Wi-Fi联盟制造商的商标作为产品的品牌认证。它可以让电脑、手机、平板电脑等设备通过无线信号连接到互联网 。 在无线网络中,AP(Access Point)和 STA(St…...
【网络虚拟化】网络设备常见冗余方式——堆叠、M-Lag、DRNI
网络设备常见冗余设计——堆叠、M-Lag、DRNI 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 网络设备常见冗余设计——堆叠、M-Lag、DRNI 网络设备常见冗余设计——堆叠、M-Lag、DRNI前言一、网络设备虚拟化二、堆叠技术1.技术原理2.…...
arm的侏罗纪二 cache学习
个人觉得inner shareable和outer shareable;POU和POC 是难点,慢慢学习吧。 inner shareable是cluster内 outer shareable是cluster之间 参考文献: 深入学习Cache系列 1: 带着几个疑问,从Cache的应用场景学起 https://www.eet-c…...

Protecting Intellectual Property of Deep NeuralNetworks with Watermarking
保护深度神经网络的知识产权与数字水印技术 ABSTRACT 深度学习是当今人工智能服务的关键组成部分,在视觉分析、语音识别、自然语言处理等多个任务方面表现出色,为人类提供了接近人类水平的能力。构建一个生产级别的深度学习模型是一项非常复杂的任务&a…...

c++学习笔记-STL案例-机房预约系统1-准备工作
前言 准备工作包括:需求分析、项目创建、主菜单实现、退出功能实现 目录 1 机房预约系统需求 1.1 简单介绍 1.2 身份介绍 1.3 机房介绍 1.4 申请介绍 1.5 系统具体要求 1.6 预约系统-主界面思维导图 2 创建项目 2.1 创建项目 2.2 添加文件 编辑 3 创建…...

AnnData:单细胞和空间组学分析的数据基石
AnnData:单细胞和空间组学分析的数据基石 今天我们来系统学习一下单细胞分析的标准数据类型——AnnData! AnnData就是有注释的数据,全称是Annotated Data。 AnnData是为了矩阵类型数据设计的,也就是长得和表格一样的数据。比如…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...