C++并发与多线程(创建多个线程)
创建和等待多个线程
基础示例
// ConsoleApplication10.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <thread>
#include <mutex>
#include <cstdint>using namespace std;void myprint(int num )
{cout << "func = " << num << " threadid = " << this_thread::get_id() << endl;std::this_thread::sleep_for(std::chrono::milliseconds(1));return;
}int main()
{cout << "=========================================== " << " threadid = " << this_thread::get_id() << endl;vector<thread>mythreads;//创建十个线程,执行函数for (int i = 0; i < 10; i++){
#if 0thread t(myprint,i);mythreads.push_back(t);
#else mythreads.push_back(thread(myprint, i)); //不能用以上写法,因为以上是一个临时对象,结束之后会销毁。 vector内容在push时,会调用拷贝构造函数,如果是一个临时变量会调用移动构造
#endif}//for(auto it: mythreads) //这样好像不行,求评论区指出正确写法。//{// it.join();//}for (int i = 0; i < 10; i++){mythreads[i].join();}cout << "=========================================== " << " threadid = " << this_thread::get_id() << endl;return 0;
}
数据共享保护案例代码
产生竞争的代码示例
// ConsoleApplication10.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <thread>
#include <mutex>
#include <cstdint>
#include <list>
using namespace std;class TA
{
public:int m_i; //mutable可以修改变量的值list<int> m_list;TA(int i) :m_i(i) // 列表初始化来初始化对象。 explicit可以禁止隐式转换{cout << "TA()构造函数被执行" << this<< " threadid = "<< this_thread::get_id() << endl;}TA(const TA& ta) :m_i(ta.m_i){cout << "TA拷贝构造函数" <<this << " threadid = " << this_thread::get_id() << endl;}TA(const TA&& ta) :m_i(ta.m_i){//m_i = 0;//ta.m_i = -100;cout << "TA移动构造函数" << this << " threadid = " << this_thread::get_id() << endl;}void thread_work(){//把收到的消息放到队列线程里。cout << "TA thread_work " << this << " threadid = " << this_thread::get_id() << endl;for (int i = 0; i < 100000;i++){m_list.push_back(i); cout << "thread_work执行,插入一个元素" << i << endl;}}void therad_out(){cout << "TA therad_out " << this << " threadid = " << this_thread::get_id() << endl;for (int i = 0; i < 100000; i++){if (!m_list.empty()){int command = m_list.front();m_list.pop_front();cout << "threadout执行,拿到的元素是" << command << endl;}elsecout << "threadout 执行,但是消息队列是空的"<< i << endl;}}~TA(){cout << "TA析构函数" << this << " threadid = " << this_thread::get_id() << endl;}
};int main()
{cout << "=========================================== " << " threadid = " << this_thread::get_id() << endl<<endl;TA ta(10);thread myoutobj(&TA::therad_out, ref(ta) ); //第二个参数使用引用可以保证使用同一个对象。thread myworkbj(&TA::thread_work, &ta); //第二个参数使用引用可以保证使用同一个对象。myoutobj.join();myworkbj.join();cout << "=========================================== " << " threadid = " << this_thread::get_id() << endl;return 0;
}
使用互斥量解决竞争(mutex)
// ConsoleApplication10.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <thread>
#include <mutex>
#include <cstdint>
#include <list>
using namespace std;class TA
{
public:int m_i; //mutable可以修改变量的值list<int> m_list;mutex m_mutex;TA(int i) :m_i(i) // 列表初始化来初始化对象。 explicit可以禁止隐式转换{cout << "TA()构造函数被执行" << this << " threadid = " << this_thread::get_id() << endl;}TA(const TA& ta) :m_i(ta.m_i){cout << "TA拷贝构造函数" << this << " threadid = " << this_thread::get_id() << endl;}TA(const TA&& ta) :m_i(ta.m_i){//m_i = 0;//ta.m_i = -100;cout << "TA移动构造函数" << this << " threadid = " << this_thread::get_id() << endl;}void thread_work(){//把收到的消息放到队列线程里。cout << "TA thread_work " << this << " threadid = " << this_thread::get_id() << endl;for (int i = 0; i < 100000; i++){m_mutex.lock();m_list.push_back(i);cout << "thread_work执行,插入一个元素" << i << endl;m_mutex.unlock();}}void therad_out(){cout << "TA therad_out " << this << " threadid = " << this_thread::get_id() << endl;int command = 0;for (int i = 0; i < 100000; i++){bool ret = outMsgProc(command);if (ret == true){cout << "threadout执行,拿到的元素是" << command << endl;}else{cout << "threadout 执行,但是消息队列是空的" << i << endl;}}}bool outMsgProc(int& command){m_mutex.lock();if (!m_list.empty()){int command = m_list.front();m_list.pop_front();m_mutex.unlock();return true;}m_mutex.unlock();return false;}~TA(){cout << "TA析构函数" << this << " threadid = " << this_thread::get_id() << endl;}
};int main()
{cout << "=========================================== " << " threadid = " << this_thread::get_id() << endl << endl;TA ta(10);thread myoutobj(&TA::therad_out, ref(ta)); //第二个参数使用引用可以保证使用同一个对象。thread myworkbj(&TA::thread_work, &ta); //第二个参数使用引用可以保证使用同一个对象。myoutobj.join();myworkbj.join();cout << "=========================================== " << " threadid = " << this_thread::get_id() << endl;return 0;
}
智能锁(lock_guard<mutex> )
bool outMsgProc(int& command){std::lock_guard<mutex> guard(m_mutex); //智能锁,出去作用域会自动释放,使用之后就不能用lock和unlock了。//m_mutex.lock();if (!m_list.empty()){int command = m_list.front();m_list.pop_front();//m_mutex.unlock();return true;}//m_mutex.unlock();return false;}
死锁问题
死锁是并发编程中的一个经典问题,发生在两个或多个线程在等待对方释放资源时永远阻塞的情况。死锁会导致程序无法继续执行,因为涉及的线程都无法继续向前推进。死锁通常由以下四个必要条件同时出现引起:
-
互斥条件:资源不能被共享,只能由一个线程占用。
-
占有并等待:线程已经持有至少一个资源,并且等待获取其他线程持有的资源。
-
不可剥夺:资源不能被强制从线程中剥夺,只能由线程自己释放。
-
循环等待:存在一个线程循环链,链中的每个线程都在等待下一个线程所持有的资源。
死锁的预防和解决策略
-
资源有序分配:为资源分配一个全局顺序,所有线程都必须按照这个顺序来请求资源。
-
避免占有并等待:线程在请求资源前不持有任何资源,或者一次性请求所有需要的资源。
-
资源剥夺:允许系统在必要时从线程中剥夺资源。
-
超时机制:线程在请求资源时设置超时,如果在超时时间内没有获取到资源,就释放已持有的资源并重试。
-
死锁检测与恢复:系统定期检测死锁,并采取恢复措施,如回滚事务或重启线程。
#include <iostream>
#include <thread>
#include <mutex>std::mutex mutex1;
std::mutex mutex2;void thread1() {mutex1.lock();std::cout << "Thread 1: Holding mutex1, waiting for mutex2." << std::endl;mutex2.lock();std::cout << "Thread 1: Holding both mutexes." << std::endl;mutex2.unlock();mutex1.unlock();
}void thread2() {mutex2.lock();std::cout << "Thread 2: Holding mutex2, waiting for mutex1." << std::endl;mutex1.lock();std::cout << "Thread 2: Holding both mutexes." << std::endl;mutex1.unlock();mutex2.unlock();
}int main() {std::thread t1(thread1);std::thread t2(thread2);t1.join();t2.join();return 0;
}
在这个例子中,thread1
和 thread2
都试图先锁定 mutex1
,然后锁定 mutex2
。如果两个线程几乎同时运行,它们将相互等待对方释放资源,从而导致死锁。
智能锁(std::lock)
std::lock
是 C++11 引入的一个函数,用于一次性锁定多个互斥锁(mutexes),从而避免死锁。它确保所有提供的互斥锁都被锁定,或者在遇到异常时,已经锁定的互斥锁会被解锁,这通过 RAII(资源获取即初始化)风格保证。
#include <mutex>
#include <thread>std::mutex mtx1, mtx2;void threadSafeFunction() {std::lock(mtx1, mtx2); // 一次性锁定两个互斥锁,要么同时锁,要么同时不锁std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);// 临界区代码,现在可以安全地访问共享资源// 无需手动解锁,lock1 和 lock2 在作用域结束时自动解锁
}
在这个例子中,std::lock_guard
的 std::adopt_lock
参数告诉 std::lock_guard
,互斥锁已经被锁定,并且 std::lock_guard
应该在析构时解锁它们。
注意事项
-
避免死锁:使用
std::lock
可以减少死锁的风险,因为它确保所有互斥锁同时被锁定或解锁。 -
异常安全:
std::lock
与std::lock_guard
结合使用,可以确保即使在抛出异常的情况下,互斥锁也能被正确解锁。 -
性能考虑:虽然
std::lock
提供了方便的一次性锁定多个互斥锁的能力,但它可能比单独锁定每个互斥锁有更高的性能开销。在性能敏感的应用中,应谨慎使用。 -
可扩展性:
std::lock
可以处理任意数量的互斥锁,这使得它在需要锁定多个资源时非常灵活。
通过使用 std::lock
和 std::lock_guard
,你可以编写更安全、更易于维护的并发代码。(谨慎使用)
智能锁(unique_lock)
std::unique_lock
是 C++11 引入的一个类模板,它提供了一种灵活的方式来管理互斥量(mutex)。与 std::lock_guard
相比,std::unique_lock
更加灵活,允许在不同的作用域和不同的锁定策略之间进行选择。以下是 std::unique_lock
的一些主要特点和用法:
特点
-
灵活性:
std::unique_lock
可以在构造时选择是否锁定互斥量,支持手动锁定和解锁,允许条件变量的等待,以及在等待条件变量时自动解锁和重新锁定。 -
避免死锁:由于
std::unique_lock
的 RAII 特性,确保在作用域结束时自动解锁,降低了因忘记解锁而引起死锁的风险。 -
可以延迟锁定:你可以在构造
unique_lock
时不锁定互斥量,并在后面需要时再手动锁定。 -
可移动:
std::unique_lock
是可移动的,但不可复制,这使得它可以在线程间安全地转移锁的所有权。
adopt_lock
- 延迟锁定:可以在构造时选择不锁定互斥量,并在需要时手动锁定。
std::adopt_lock
是 C+++11 引入的一个标签类型,用于指示 std::unique_lock
或 std::lock_guard
在构造时不要尝试去锁定传入的互斥锁(mutex),因为互斥锁已经被当前线程锁定。这个标签主要用于在已经手动锁定互斥锁的情况下,将互斥锁的管理权转移给 std::unique_lock
或 std::lock_guard
对象,以利用它们的异常安全保证(RAII)。
使用 std::adopt_lock
时,你必须确保在构造 std::unique_lock
或 std::lock_guard
之前,互斥锁已经被当前线程锁定。这通常用于避免在已经手动锁定互斥锁的情况下,再次尝试锁定互斥锁,从而提高效率。
#include <mutex>
#include <thread>
#include <iostream>std::mutex mtx;void print_thread_id(int id) {mtx.lock(); // 手动锁定互斥锁std::lock_guard<std::mutex> lck(mtx, std::adopt_lock); // 告诉 lock_guard 互斥锁已经被锁定std::cout << "thread #" << id << '\n';mtx.unlock(); // 手动解锁互斥锁
}int main() {std::thread threads[10];for (int i = 0; i < 10; ++i)threads[i] = std::thread(print_thread_id, i + 1);for (auto& th : threads) th.join();return 0;
}
try_to_lock
- 递归锁定:允许同一个线程多次锁定同一个互斥量。
std::unique_lock
提供了一种灵活的方式来管理互斥锁(mutex),它允许你尝试锁定互斥锁而不必真正锁定它。try_to_lock
是 std::unique_lock
的一个构造参数选项,用于实现这种尝试锁定的行为。
当你使用 std::try_to_lock
作为 std::unique_lock
的构造函数参数时,互斥锁不会立即被锁定。相反,std::unique_lock
会尝试锁定互斥锁,如果互斥锁已经被其他线程锁定,则不会阻塞调用线程,而是立即返回。这允许你实现非阻塞的锁定机制。
#include <mutex>
#include <thread>
#include <iostream>std::mutex mtx;void threadSafeFunction() {std::unique_lock<std::mutex> lock(mtx, std::try_to_lock);if (lock.owns_lock()) {// 如果成功锁定,执行临界区代码std::cout << "Thread " << std::this_thread::get_id() << " has the lock." << std::endl;} else {// 如果未能锁定,可以执行其他操作或重试std::cout << "Thread " << std::this_thread::get_id() << " could not get the lock." << std::endl;}
}int main() {std::thread t1(threadSafeFunction);std::thread t2(threadSafeFunction);t1.join();t2.join();return 0;
}
defer_lock
在 C++ 中,std::unique_lock
提供了一种灵活的互斥锁管理方式,它允许延迟锁定(defer locking)。std::defer_lock
是 std::unique_lock
的构造函数的一个可选参数,用于指示 std::unique_lock
的实例在初始化时不立即锁定互斥锁,而是将其保持在未锁定状态。这使得开发者可以在之后的某个时刻显式地调用 lock
方法来获取锁。
使用 std::defer_lock
的优点包括:
- 延迟锁定:允许开发者在构造
std::unique_lock
实例后,根据需要决定何时锁定互斥锁。 - 避免死锁:通过延迟锁定,可以减少在获取多个锁时发生死锁的风险。
- 灵活性:提供了在尝试锁定之前执行其他操作的能力,例如检查条件或执行初始化。
#include <mutex>
#include <thread>
#include <iostream>std::mutex mtx;void threadSafeFunction() {std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // 延迟锁定// 执行一些不需要互斥的操作// ...// 现在锁定互斥锁lock.lock();// 临界区代码,现在可以安全地访问共享资源std::cout << "Thread " << std::this_thread::get_id() << " has the lock." << std::endl;// 离开作用域时自动解锁
}int main() {std::thread t1(threadSafeFunction);std::thread t2(threadSafeFunction);t1.join();t2.join();return 0;
}
release
std::unique_lock
的 release
成员函数用于释放与互斥锁(mutex)的关联,但不解锁互斥锁。当你调用 release
方法后,std::unique_lock
实例将不再管理互斥锁,这意味着它不会在析构时解锁互斥锁。这允许你将互斥锁的控制权显式地转移给其他 std::unique_lock
实例或手动管理互斥锁。
使用 release
方法后,你需要确保互斥锁在不再需要时被正确解锁,因为 std::unique_lock
不再负责解锁操作。
#include <mutex>
#include <thread>
#include <iostream>std::mutex mtx;void transferLock() {std::unique_lock<std::mutex> lock(mtx);// 临界区代码std::cout << "Thread " << std::this_thread::get_id() << " has the lock." << std::endl;// 释放互斥锁的控制权,但不解锁lock.release();
}void manualUnlock() {// 直接使用已经释放的互斥锁mtx.unlock();std::cout << "Thread " << std::this_thread::get_id() << " manually unlocked the mutex." << std::endl;
}int main() {std::thread t1(transferLock);std::thread t2(manualUnlock);t1.join();t2.join();return 0;
}
单例设计模式分析与解决
// ConsoleApplication10.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <thread>
#include <mutex>
#include <cstdint>
#include <list>
using namespace std;class MyCls
{
public:// 提供一个全局访问点,用于获取类的唯一实例static MyCls* m_inst;static MyCls* instance(){if (m_inst == nullptr){m_inst = new MyCls();static CGar c1;}return m_inst;}class CGar{public:~CGar(){if (MyCls::m_inst){delete MyCls::m_inst;MyCls::m_inst = NULL;cout << "单例数据被释放了" << endl;}}};static MyCls* instance1(){static MyCls* inst = new MyCls;return inst;}};
MyCls* MyCls::m_inst = NULL;int main()
{cout << "=========================================== " << " threadid = " << this_thread::get_id() << endl << endl;cout << MyCls::instance() << endl;cout << MyCls::instance() << endl;cout << MyCls::instance1() << endl;cout << MyCls::instance1() << endl;cout << "=========================================== " << " threadid = " << this_thread::get_id() << endl;return 0;
}
多线程时问题与解决
// ConsoleApplication10.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <thread>
#include <mutex>
#include <cstdint>
#include <list>
using namespace std;class MyCls
{
public:// 提供一个全局访问点,用于获取类的唯一实例static MyCls* m_inst;static MyCls* instance(){if (m_inst == nullptr){this_thread::sleep_for(std::chrono::microseconds(1000));static CGar c1;m_inst = new MyCls();}return m_inst;}class CGar{public:~CGar(){if (MyCls::m_inst){delete MyCls::m_inst;MyCls::m_inst = NULL;cout << "单例数据被释放了" << endl;}}};static MyCls* instance1(){this_thread::sleep_for(std::chrono::microseconds(1000));//方式一//static MyCls* inst = new MyCls; //在C++11之后,这种写法是安全的//return inst;//方式二static MyCls inst;return &inst;}};
MyCls* MyCls::m_inst = NULL;void mythread()
{ cout << "mythread start" << endl;MyCls* me = MyCls::instance1();cout << "me = " << me;cout << "mythread end" << endl;
}int main()
{cout << "=========================================== " << " threadid = " << this_thread::get_id() << endl << endl;//cout << MyCls::instance() << endl;//cout << MyCls::instance() << endl;std::thread obj1(mythread);std::thread obj2(mythread);obj1.join();obj2.join();//cout << MyCls::instance1() << endl;//cout << MyCls::instance1() << endl;cout << "=========================================== " << " threadid = " << this_thread::get_id() << endl;return 0;
}
call_once
// ConsoleApplication10.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <thread>
#include <mutex>
#include <cstdint>
#include <list>
using namespace std;std::mutex g_mut;std::once_flag g_flag;class MyCls
{
public:// 提供一个全局访问点,用于获取类的唯一实例static MyCls* m_inst;static MyCls* instance(){if (m_inst != nullptr)return m_inst; //使用双检索进行判断。 std::unique_lock<std::mutex> mymut(g_mut); //自动加锁,出作用域自动释放。if (m_inst == nullptr){this_thread::sleep_for(std::chrono::microseconds(1000));static CGar c1;m_inst = new MyCls();}return m_inst;}class CGar{public:~CGar(){if (MyCls::m_inst){delete MyCls::m_inst;MyCls::m_inst = NULL;cout << "单例数据被释放了" << endl;}}};static MyCls* instance1(){this_thread::sleep_for(std::chrono::microseconds(1000));//方式一//static MyCls* inst = new MyCls; //在C++11之后,这种写法是安全的//return inst;//方式二static MyCls inst;return &inst;}};
MyCls* MyCls::m_inst = NULL;void mythread()
{ cout << "mythread start" << endl;MyCls* me = MyCls::instance();cout << "me = " << me;cout << "mythread end" << endl;
}int main()
{cout << "=========================================== " << " threadid = " << this_thread::get_id() << endl << endl;//cout << MyCls::instance() << endl;//cout << MyCls::instance() << endl;#if 1std::thread obj1(mythread);std::thread obj2(mythread);obj1.join();obj2.join();
#endif//std::call_once(std::once_flag::once_flag,mythread);//call_once保证函数只调用一次,具备互斥量能力std::call_once(g_flag, mythread);std::call_once(g_flag, mythread);//cout << MyCls::instance1() << endl;//cout << MyCls::instance1() << endl;cout << "=========================================== " << " threadid = " << this_thread::get_id() << endl;return 0;
}
相关文章:
C++并发与多线程(创建多个线程)
创建和等待多个线程 基础示例 // ConsoleApplication10.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 //#include <iostream> #include <vector> #include <map> #include <string> #include <thread> #include <…...
【开发日志】ASP.NET Core Minimal APIs开发日志
后端 实现登录注册 注册API 在数据库中存储/注册账户密码 登录API 检测接收来的账户密码,如果正确,则生成JWT Token返回给客户端 未配置密钥 报错信息,这是我在提交注册请求时,后端报的错,看起来是在生成JWT Token时出现了…...
5G学习笔记之Non-Public Network R18
只是协议的搬运工 目录 0. NPN其它笔记 1. 概述 2. R18增强 2.1 等效SNPN间的移动性管理 2.2 non-3GPP接入SNPN 2.3 Localized Service 2.4 Charging 2.5 Management 0. NPN其它笔记 1. SNPN系列ID和广播消息 1. 概述 NPN,Non-Public Network, 非公共网络…...
sheng的学习笔记-AI-WaveNet模型
Ai目录:sheng的学习笔记-AI目录-CSDN博客 需要先看一下这些文章,作为基础 sheng的学习笔记-AI-残差网络-Residual Networks (ResNets)_神经网络的衰变是什么-CSDN博客 sheng的学习笔记-AI-卷积神经网络_单层卷积神经网络-CSDN博客 sheng的学习笔记-T…...
0002.基于springboot +layui二手物品交易平台
适合初学同学练手项目,部署简单,代码简洁清晰; 注:当前项目架构使用前后端未分离哦! 一、系统架构 前端:layui| html 后端:springboot | mybatis-plus 环境:jdk1.8 | mysql | maven 二、代…...
java集合基础
Java的java.util包主要提供了以下三种类型的集合: List:一种有序列表的集合,例如,按索引排列的Student的List;Set:一种保证没有重复元素的集合,例如,所有无重复名称的Student的Set&…...
如何在NGINX中实现基于IP的访问控制(IP黑白名单)?
大家好,我是锋哥。今天分享关于【如何在NGINX中实现基于IP的访问控制(IP黑白名单)?】面试题。希望对大家有帮助; 如何在NGINX中实现基于IP的访问控制(IP黑白名单)? 1000道 互联网大…...
「Mac玩转仓颉内测版51」基础篇13 - 高阶函数与闭包
本篇详细介绍高阶函数和闭包,这是仓颉语言中实现灵活逻辑的关键工具。高阶函数可将函数作为参数或返回值使用,而闭包能捕获其定义域中的变量,并在后续调用中保持状态。这些概念能让代码更加简洁、灵活,并提升复用性。 关键词 高阶…...
如何与GPT更高效的问答
与GPT进行高效沟通的关键在于提问的方式。通过合理的提问技巧,可以更清晰地表达需求,从而获得更准确的回答。以下是一些实用的建议,帮助你提升与GPT的交流效率。 1. 使用简单明了的语言: 尽量避免使用复杂的术语和行话,…...
【Android】解决 ADB 中 SELinux 设置与 `Failed transaction (2147483646)` 错误
解决 ADB 中 SELinux 设置与 Failed transaction (2147483646) 错误 在使用 ADB 进行开发和调试时,经常会遇到由于 Android 系统安全策略(SELinux)引起的权限问题,尤其是在执行某些操作时,可能会遇到类似 cmd: Failur…...
etcd常用监控
通过部署etcd-exporterPrometheus,然后配置etcd相关告警可以及时发现etcd集群风险 常见监控项目 1. etcd集群无leader Etcd cluster have no leader - alert:EtcdNoLeaderexpr: etcd_server_has_leader 0 for:0mlabels:severity: criticalannotations:summary:Et…...
红日靶场vulnstack 7靶机的测试报告[细节](一)
目录 一、测试环境 1、系统环境 2、注意事项 3、使用工具/软件 二、测试目的 三、操作过程 1、信息搜集 2、Redis未授权访问漏洞获取web1靶机系统权限 3、获取docker靶机系统权限 ①Laravel框架漏洞利用getshell ②Laravel主机的提权&&docker容器逃逸 提权…...
【计算机网络】Layer4-Transport layer
目录 传输层协议How demultiplexing works in transport layer(传输层如何进行分用)分用(Demultiplexing)的定义:TCP/UDP段格式: UDPUDP的特点:UDP Format端口号Trivial File Transfer Protocol…...
【conda/cuda/cudnn/tensorrt】一份简洁的深度学习环境安装清单
🚀本文主要总结一下conda、cuda、cudnn、tensorrt的快速安装。至于nvidia显卡驱动的安装,暂且不提。本文适合有一定反复安装经验的读者😂,方便其快速整理安装思路。 NVIDIA Drivers 🌔01conda ⭐️ 注意,c…...
在C语言中,访问结构体的成员时,什么时候用`.`【符号点】,什么时候用符号`->`?
在C语言中,访问结构体成员时,使用.和->的情况取决于你是否通过结构体指针来访问。 .(点运算符):当你有一个结构体变量时,使用点运算符来访问它的成员。例如: struct Person {char name[50];i…...
Java序列化
Java序列化 简单来说: 序列化是将对象的状态信息转换为可以存储或传输的形式(如字节序列)的过程。在 Java 中,通过序列化可以把一个对象保存到文件、通过网络传输到其他地方或者存储到数据库等。最直接的原因就是某些场景下需要…...
Python 方框消除小游戏
import pygame import random# 初始化pygame pygame.init()# 设置屏幕大小 screen pygame.display.set_mode((800, 600))# 设置标题 pygame.display.set_caption("打砖块")# 定义颜色 WHITE (255, 255, 255) BLACK (0, 0, 0) RED (255, 0, 0) GREEN (0, 255, 0)…...
微软 Phi-4:小型模型的推理能力大突破
在人工智能领域,语言模型的发展日新月异。微软作为行业的重要参与者,一直致力于推动语言模型技术的进步。近日,微软推出了最新的小型语言模型 Phi-4,这款模型以其卓越的复杂推理能力和在数学领域的出色表现,引起了广泛…...
OkHttp源码分析:分发器任务调配,拦截器责任链设计,连接池socket复用
目录 一,分发器和拦截器 二,分发器处理异步请求 1.分发器处理入口 2.分发器工作流程 3.分发器中的线程池设计 三,分发器处理同步请求 四,拦截器处理请求 1.责任链设计模式 2.拦截器工作原理 3.OkHttp五大拦截器 一&#…...
前后端跨域问题(CROS)
前端 在src中创建util文件,写request.js文件: request.js代码如下: import axios from axios import { ElMessage } from element-plus;const request axios.create({// baseURL: /api, // 注意!! 这里是全局统一加…...
ctfshow xss
1.web316 看的wp 先在服务器上写一个php文件 <?php$cookie $_GET[cookie];$time date(Y-m-d h:i:s, time());$log fopen("cookie.txt", "a");fwrite($log,$time.: . $cookie . "\n");fclose($log); ?> 获取cookie的值ÿ…...
kafka客户端调用
kafka客户端调用 springboot整合kafkajava调用kafka其他问题 springboot整合kafka 手动提交需要在配置文件配置kafka属性 kafka.listener.ack-mode: manual Component public class MyKafkaListener {Autowiredprivate SaslClient saslClient;//监听所有分区KafkaListener(top…...
Linux 中 sftp 命令基本使用
参考链接 sftp 命令_sftp命令-CSDN博客 登录服务器【必须】 # sftp userNamehost # 例如 sftp root8.138.86.224 上传文件到服务器 使用 sftp 命令可以将本地文件上传到远程主机 # put local_file remote_file # 例如: put E://1.mp4 /root/1.mp4 下载文件 使…...
xtu oj 3个矩形与1个正方形
文章目录 回顾前言代码思路 回顾 xtu oj 神经网络xtu oj 1167 逆序数(大数据)xtu oj 原根xtu oj 不定方程的正整数解xtu oj 最多的可变换字符串xtu oj String Ixtu oj 字母序列xtu oj 分段xtu oj 完全平方数IIxtu oj 连接字符串xtu oj 2021xtu oj 数字x…...
C++ 引用
引用(Reference)是C语言中用于给变量起别名的特性,是一种轻量级的变量访问方式。通过引用,可以对原变量进行操作而不需要直接访问原变量的内存地址。这一特性极大地增强了代码的简洁性和安全性,同时也在参数传递和返回…...
解决几个常见的ASP.NET Core Web API 中多线程并发写入数据库失败的问题
前言 在ASP.NET Core Web API应用程序中,当多个并发线程同时调用新增用户数据的接口时,可能会遇到数据库写入失败的问题。这个问题通常源于多个线程同时访问数据库时,可能会导致以下情况: 数据库连接池耗尽:每个线程…...
让知识更具生命力
在当今快速发展的技术世界中,技术文档的重要性不言而喻。它不仅是知识传递的有效载体,也是团队协作的基石,更是提升产品竞争力的重要工具。然而,编写出一份清晰、完整且实用的技术文档,对于许多开发者和团队来说并非易…...
批量DWG文件转dxf(CAD图转dxf)——c#插件实现
此插件可将指定文件夹及子文件夹下的dwg文件批量转为dxf文件。 (使用方法:命令行输入 “netload” 加载插件,然后输入“dwg2dxf”运行,选择文件夹即可。) 生成dxf在此新建的文件夹路径下,包含子文件夹内的…...
《Django 5 By Example》阅读笔记:p561-p613
《Django 5 By Example》学习第 21 天,p561-p613 总结,总计 53 页。 一、技术总结 1.mixins (1)定义(什么是 mixins?) p570,Mixins are a special kind of multiple inheritance for a class. (2)适用场景(为什么使用?) 1)…...
1. 字符串分割
给定一个非空字符串S,其被N个‘-’分隔成N1的子串,给定正整数K,要求除第一个子串外,其余的子串每K个字符组成新的子串,并用‘-’分隔。对于新组成的每一个子串,如果它含有的小写字母比大写字母多࿰…...
[SAP ABAP] 将内表数据转换为HTML格式
从sflight数据库表中检索航班信息,并将这些信息转换成HTML格式,然后下载或显示在前端 开发步骤 ① 自定义一个数据类型 ty_sflight 来存储航班信息 ② 声明内表和工作区变量,用于存储表头、字段、HTML内容和航班详细信息以及创建字段目录lt…...
计算机网络-应用层
应用层是咱们日常开发中,最常用到的一层 主要涉及到两种情况: 1.使用大佬们已经创建好的应用层协议(后面再讨论,应用层知名的协议有很多,其中的佼佼者就是 HTTP (后面会出单独的文章来讲解))2.自己定义应用…...
SpringEvent 解决 WebUploader 大文件上传解耦问题
一、SpringEvent涉及的相关组件 为了让不熟悉SpringEvent的朋友对Event也有一个大致的印象。这里还是对SpringEvent对象包含的方法和相关组件的应用进行简单的介绍。 1、 事件(Event) 事件是应用程序中发生的某种事情,可以是用户行为、系统…...
KALI安装操作及过程
以下是在计算机上安装 Kali Linux 的详细教程:(通常我直接使用虚拟机) 解压虚拟机安装包,直接在虚拟机中打开KALI (将内存改为4GB) 初始密码账号:kali 一、准备工作 下载 Kali Linux 镜像文件…...
Scala—“==“和“equals“用法(附与Java对比)
Scala 字符串比较—""和"equals"用法 Scala 的 在 Scala 中, 是一个方法调用,实际上等价于调用 equals 方法。不仅适用于字符串,还可以用于任何类型,并且自动处理 null。 Demo: Java 的 在 J…...
[Flutter] : Clipboard
import package:flutter/material.dart; import package:flutter/services.dart; setData Clipboard.setData(ClipboardData(text: "传入的文字内容")); getData Clipboard.getData(Clipboard.kTextPlain) 记录 | Flutter剪切板-刨根问底做一个可以在后台…...
vue2:v-for实现的el-radio-group选中时显示角标,并自定义选中按钮的字体颜色和背景色
项目中需要实现一组预定义查询,每一个查询按钮在选中时右上角显示一个角标,展示当前查询返回的数据条目。 1、text-color="#3785FF" fill="#E6EAF1" 处理选中时的字体颜色和背景色,如上图,分别为蓝色和浅灰色。 2、badge中:value="selectedRadio…...
Dynamics 365 CRM- 后端
Dynamics 365 CRM 后端插件语法示例 public IPluginExecutionContext context null;//上下文 public IOrganizationServiceFactory serviceFactory null;//组织服务工厂对象 public IOrganizationService service null;//Org服务对象//创建执行上下文 context (IPluginExe…...
电脑显示器选购指南2024
选择显示器是五花八门的显示参数,如何选择,以下给出参数说明,及部分参考: 1. 尺寸和分辨率 尺寸(英寸) 根据使用距离和用途选择合适的屏幕尺寸: 21-24 英寸:适合小桌面空间、日常…...
机器学习-多元线性回归
文章目录 代码什么是回归任务什么是多元什么是回归什么是多元线性回归表达式何时使用多元线性回归注意损失函数 代码 https://github.com/FULLK/AI_Study/tree/main/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0-%E5%A4%9A%E5%85%83%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92 什么是回归…...
WEB语义化的新探索:浅析LLMs.txt
【引】有人迷恋使用大模型生成各种有趣的内容, 有人沉醉于大模型相关技术的探索,没有对错,只在于你的乐趣所在。 一项名为 llms.txt 的新提案标志了一些非同寻常的东西的出现: 一个Web网站不仅为人类读者服务,而且为人工智能提供服…...
【经典】制造供应链四类策略(MTS、MTO、ATO、ETO)细说
关注作者 制造供应链的牛鞭问题与复杂问题主要是从两个方面解决,一是同步化供应链消减从需求到供应的放大效应,二是供应链细分,针对不同的客户、不同的需求供应的匹配策略来应对复杂性,更好的满足客户并以最低的总成本来实现。 对…...
RabbitMQ中的Publish-Subscribe模式
在现代分布式系统中,消息队列(Message Queue)是实现异步通信和解耦系统的关键组件。RabbitMQ 是一个功能强大且广泛使用的开源消息代理,支持多种消息传递模式。其中,Publish/Subscribe(发布/订阅࿰…...
简单了解一下 Go 语言的构建约束?
构建约束是一种在 Go 语言中控制源文件编译条件的方法,它可以让您指定某些文件只在特定的操作系统、架构、编译器或 Go 版本下编译,而在其他环境中自动忽略。这样可以方便您针对不同的平台或场景编写不同的代码,实现条件编译的功能。 构建…...
图像融合算法笔记2024 CDTNet
目录 ControlCom-Image-Composition CDTNet-High-Resolution-Image-Harmonization 依赖项: trilinear 效果图: 推理代码ok 只支持linux系统: ControlCom-Image-Composition CDTNet-High-Resolution-Image-Harmonization 开源地址: GitHub - bcmi/CDTNet-High-Reso…...
我们来对接蓝凌OA --报文格式
题记 数智化办公专家、国家高新技术企业、知识管理国家标准制定者、信创供应商10强…等等,这些和咱们有关系吗!!不好意思,走错片场了,刚和项目经理在甲方那边吹牛B想想刚刚的大饼,看看支付宝余额ÿ…...
npm、yarn、pnpm三者的异同
这个表格将会说明一切: 特性npmyarnpnpm依赖管理方式扁平化管理,嵌套依赖树,可能重复安装扁平化管理喝符号链接,同版本只能安装一次基于硬链接喝符号链接的内容寻址存储安装速度最慢中等(并行安装)最快(得益于硬链接的复用)磁盘空…...
纯CSS实现文本或表格特效(连续滚动与首尾相连)
纯CSS实现文本连续向左滚动首尾相连 1.效果图: 2.实现代码: <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, init…...
信号处理:概念、技术、领域
目录 基本概念 主要技术 应用领域 信号处理是一个涉及分析、修改和再生信号的多学科领域。信号可以是各种形式的,例如声音、图像、视频或其他类型的监测数据。信号处理的主要目标是提取有用的信息并增强信号的质量。以下是信号处理的一些基本概念和应用ÿ…...
Android 中 Activity 和 Fragment 的结合使用经典案例
学习笔记 0. 分析 Activity 与 Fragment 的区别,部分使用的差异 上一篇中我们分析了Activity 与 Fragment 的区别,部分使用的差异。 点我跳转上一篇 1. 单个 Activity 中使用多个 Fragment 这是最常见的用法之一,特别是在单屏幕应用中。通…...