C++多线程同步总结

news2024/11/11 23:26:01

C++多线程同步总结

关于C++多线程同步

一、C++11规范下的线程库

1、C++11 线程库的基本用法:创建线程、分离线程

#include<iostream>
#include<thread>
#include<windows.h>
using namespace std;
void threadProc()
{
    cout<<"this is in threadProc\n";
    cout<<"thread1's id is "<<this_thread::get_id()<<endl; //获取所属线程的id
}
void threadProc2(int num)
{
    cout<<"thread num = "<<num<<endl;
}
void threadProc3()
{
    cout<<"this thread is detached\n";
}
void threadProc4()
{
    cout<<"this thread is detached and won't print in the same console.'\n";
}
int main()
{
    thread a;//创建线程1,定义线程,后面再分配任务
    a = thread(threadProc);
    thread b(threadProc2,5);//创建线程2 ,定义线程的时候分配任务,参数类似于printf一样,可以为多个
    a.join();
    b.join();//采用join,主线程会阻塞等待子线程执行完毕
    thread c(threadProc3);
    c.detach();//采用detach,主线程不会等,这个线程开启早,还能输出到主线程的控制台
    cout<<"main thread exit"<<endl;
    thread d(threadProc4);
    d.detach();//
}

运行结果:

2、基本的互斥锁

上述运行,输出语句显然没有顺序执行,为了达到一行一行输出的效果,可以使用最基本的互斥锁。

#include<iostream>
#include<thread>
#include<mutex>
using namespace std;
mutex mu;//互斥锁 
void test1()
{
    for(int i=0;i<5;i++)
    {
//        mu.lock();//锁住 
        cout<<"test1 i = "<<i<<endl;
//        mu.unlock();//释放 
    }
}
void test2()
{
    for(int j=0;j<5;j++)
    {
//        mu.lock();
        cout<<"test2 j = "<<j<<endl;
//        mu.unlock();
    }
}
int main()
{
    thread a(test1);
    thread b(test2);
    a.join();
    b.join();
    cout<<"main thread finish."<<endl;
} 

运行结果:

不加锁的话,输出就会混乱。

这里打开4行注释,重新运行。

运行结果:

可以简单理解为:test1获得锁以后,test2调用lock(),就会阻塞执行,直到test1()调用unlock()释放锁。

3、lock_guard

#include <iostream>
#include <thread>
#include <mutex>

mutex mu;//互斥锁 
/*
lock_guard<mutex> locka(mu);
作用范围为从这一行开始,到那一次循环结束,还不用自己手动解锁。 
*/
void test3()
{
    for(int i=0;i<5;i++)
    {
        std::lock_guard<std::mutex> locka(mu); 
        std::cout << "test3 i = "<< i << std::endl;
    }
}
void test4()
{
    for(int j=0;j<5;j++)
    {
        std::lock_guard<std::mutex> lock(mu);
        std::cout << "test4 j = " << j << std::endl;
    }
}
int main()
{
    std::thread a(test3);
    std::thread b(test4);
    a.join();
    b.join();
    std::cout<<"main thread finish."<<std::endl;
} 

运行结果:

4、unique_lock

#include<iostream>
#include<thread>
#include<mutex>
using namespace std;
mutex mu;//互斥锁 
void test5()
{
    for(int i=0;i<5;i++)
    {
        unique_lock<mutex> locka(mu,defer_lock); 
        cout<<"test5 i = "<<i<<endl;
        
        locka.lock();
        cout<<"this is lock1"<<endl;
    }
}
void test6()
{
    for(int j=0;j<5;j++)
    {
        unique_lock<mutex> locka(mu); 
        cout<<"test6 j = "<<j<<endl;
        locka.unlock();
        locka.lock();
        cout<<"this is lock2"<<endl;
    }
}
int main()
{
    thread a(test5);
    thread b(test6);
    a.join();
    b.join();
    cout<<"main thread finish."<<endl;
} 

运行结果:

 5、condition_variable

#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>

using namespace std;

mutex mu;
condition_variable cv;
bool print = false;
void test7()
{
    for(int i=0;i<5;i++)
    {
        unique_lock<mutex> l(mu);
        cout<<"test7 i = "<<i<<endl;
        cv.notify_one();
        print = true;
    }
}
void test8()
{
    for(int j=0;j<5;j++)
    {
        unique_lock<mutex> l(mu);
        if(!print)
        {
            cv.wait(l);
        }
        cout<<"test8 j = "<<j<<endl;
        print = false;
    }
}
int main()
{
    thread a(test7);
    thread b(test8);
    a.join();
    b.join();
}

运行结果:

二、Win32 API 实现线程同步

1、临界区

#include <iostream>
#include <thread>
#include <windows.h>

using namespace std;

CRITICAL_SECTION section;//临界区变量

void test01()
{
    for(int i=0;i<5;i++)
    {
        EnterCriticalSection(&section);//类似于 mutex.lock() 
        cout<<"this is test01 i = "<<i<<endl;
     Sleep(1);
        LeaveCriticalSection(&section);//类似于 mutex.unlock() 
    }
} 
void test02()
{
    for(int j=0;j<5;j++)
    {
        EnterCriticalSection(&section);
        cout<<"this is test02 j = "<<j<<endl;
     Sleep(1);
        LeaveCriticalSection(&section);
    }
}
int main()
{
    InitializeCriticalSection(&section);//初始化临界区对象
    
    thread a(test01);
    thread b(test02);
    a.join();
    b.join();
    DeleteCriticalSection(&section);//用完了,就删除临界区 
}

运行结果:

效果类似于mutex,只是都要在执行完循环进行解锁的操作。

2、互斥锁

#include<iostream>
#include<thread>
#include<windows.h>
using namespace std;
HANDLE hmutex;
void test03()
{
    for(int i=0;i<5;i++)
    {
        WaitForSingleObject(hmutex,INFINITE);//类似于mutex.lock() 阻塞等待多少时间 
        cout<<"test03 i = "<<i<<endl;
        ReleaseMutex(hmutex);//类似于mutex.unlock() 释放互斥锁 
    }
}
void test04()
{
    for(int j=0;j<5;j++)
    {
        WaitForSingleObject(hmutex,INFINITE);
        cout<<"test04 j = "<<j<<endl;
        ReleaseMutex(hmutex);
    }
}
int main()
{
    hmutex = CreateMutex(NULL,FALSE,"mutex");//创建一个互斥锁 
    
    thread a(test03);
    thread b(test04);
    a.join();
    b.join();
    
    CloseHandle(hmutex);//释放句柄 
}

运行结果:

3、事件

#include<iostream>
#include<thread>
#include<windows.h>

using namespace std;

HANDLE hevent;
void test05()
{
    for(int i=0;i<5;i++)
    {
        WaitForSingleObject(hevent,INFINITE);//类似于mutex.lock() 阻塞等待多少时间 
        cout<<"test05 i = "<<i<<endl;
        SetEvent(hevent);//类似于mutex.unlock() 释放互斥锁 
    }
}
void test06()
{
    for(int j=0;j<5;j++)
    {
        WaitForSingleObject(hevent,INFINITE);
        cout<<"test06 j = "<<j<<endl;
        SetEvent(hevent);
    }
}
int main()
{
    hevent = CreateEvent(NULL,FALSE,TRUE,"event");//创建一个事件 
    
    thread a(test05);
    thread b(test06);
    a.join();
    b.join();
    
    CloseHandle(hevent);//释放句柄 
}

运行结果:

4、信号量

#include <iostream>
#include <thread>
#include <windows.h>

using namespace std;

HANDLE sem;
void test07()
{
    for(int i=0;i<5;i++)
    {
        WaitForSingleObject(sem,INFINITE);//类似于mutex.lock() 阻塞等待多少时间 
        cout<<"test07 i = "<<i<<endl;
        ReleaseSemaphore(sem,1,NULL);//类似于mutex.unlock() 释放互斥锁 
    }
}
void test08()
{
    for(int j=0;j<5;j++)
    {
        WaitForSingleObject(sem,INFINITE);
        cout<<"test08 j = "<<j<<endl;
        ReleaseSemaphore(sem,1,NULL);
    }
}
int main()
{
    sem = CreateSemaphore(NULL,1,2,"semaphore");
    
    thread a(test07);
    thread b(test08);
    a.join();
    b.join();
    
    CloseHandle(sem);//释放句柄 
}

运行结果:

#include <iostream>
#include <fstream>
#include <random>
#include <ctime>

#include <windows.h>
//#include <time.h>
#include <stdio.h>
#include <math.h>
#include <bitset>

#include <thread>
#include <mutex>
#include <condition_variable>


#define NAME_LINE   40
void* g_hMutex2 = NULL; //使用适当的初始化方式
//定义线程函数传入参数的结构体
typedef struct __TICKET
{
	int nCount;
	char strTicketName[NAME_LINE];

	__TICKET() : nCount(0)
	{
		memset(strTicketName, 0, NAME_LINE * sizeof(char));
	}
}TICKET;

typedef struct __THD_DATA
{
	TICKET* pTicket;
	char strThreadName[NAME_LINE];

	__THD_DATA() : pTicket(NULL)
	{
		memset(strThreadName, 0, NAME_LINE * sizeof(char));
	}
}THD_DATA;

//基本类型数据转换成字符串
template<class T>
std::string convertToString(const T val)
{
	std::string s;
	std::strstream ss;
	ss << val;
	ss >> s;
	return s;
}
//售票程序
DWORD WINAPI SaleTicket(LPVOID lpParameter);

//售票系统
void Test2();



// 一个mutex变量控制同一个资源,因此会先打印完*再打印$
// 两个mutex变量则可能出现交替打印,因为不是修改统一资源
std::mutex mtx;  // mutex for critical section
void print_block(int n, char c)
{
	mtx.lock();
	for (int i = 0; i<n; i++)
	{
		std::cout << c;
	}
	std::cout << '\n';
	mtx.unlock();
}
void thread_1()
{
	std::cout << "子线程1" << std::endl;
}
void thread_2(int x)
{
	std::cout << "x:" << x << std::endl;
	std::cout << "子线程2" << std::endl;
}
int f_multi_thread()
{
	std::thread first(thread_1); // 开启线程,调用:thread_1()
	std::thread second(thread_2, 100); // 开启线程,调用:thread_2(100)
	//std::thread third(thread_2,3);//开启第3个线程,共享thread_2函数。
	std::cout << "主线程\n";
	first.join(); //join()等待线程结束并清理资源(会阻塞)        
	second.join();
	std::cout << "子线程结束.\n";//必须join完成


	//std::thread th1(print_block, 50, '*');//线程1:打印*
	//std::thread th2(print_block, 50, '$');//线程2:打印$
	//th1.join();
	//th2.join();

	return 0;
}

void threadProc()
{
	std::cout << "this is in threadProc\n";
	std::cout << "thread1's id is " << std::this_thread::get_id() << std::endl; //获取所属线程的id
}
void threadProc2(int num)
{
	std::cout << "thread num = " << num << std::endl;
}
void threadProc3()
{
	std::cout << "this thread is detached\n";
}
void threadProc4()
{
	std::cout << "this thread is detached and won't print in the same console.'\n";
}
std::mutex mu;//互斥锁 
void test1()
{
	for (int i = 0; i < 5; i++)
	{
		mu.lock();//锁住 
		std::cout << "test1 i = " << i << std::endl;
	    mu.unlock();//释放 
	}
}
void test2()
{
	for (int j = 0; j < 5; j++)
	{
		mu.lock();
		std::cout << "test2 j = " << j << std::endl;
		mu.unlock();
	}
}
/*
lock_guard<mutex> locka(mu);
作用范围为从这一行开始,到那一次循环结束,还不用自己手动解锁。
*/
void test3()
{
	for (int i = 0; i < 5; i++)
	{
		std::lock_guard<std::mutex> locka(mu);
		std::cout << "test3 i = " << i << std::endl;
	}
}
void test4()
{
	for (int j = 0; j < 5; j++)
	{
		std::lock_guard<std::mutex> lock(mu);
		std::cout << "test4 j = " << j << std::endl;
	}
}
void test5()
{
	for (int i = 0; i < 5; i++)
	{
		std::unique_lock<std::mutex> locka(mu, std::defer_lock);
		std::cout << "test5 i = " << i << std::endl;

		locka.lock();
		std::cout << "this is lock1" << std::endl;
	}
}
void test6()
{
	for (int j = 0; j < 5; j++)
	{
		std::unique_lock<std::mutex> locka(mu);
		std::cout << "test6 j = " << j << std::endl;
		locka.unlock();
		locka.lock();
		std::cout << "this is lock2" << std::endl;
	}
}
std::condition_variable cv;
bool print = false;
void test7()
{
	for (int i = 0; i < 5; i++)
	{
		std::unique_lock<std::mutex> l(mu);
		std::cout << "test7 i = " << i << std::endl;
		cv.notify_one();
		print = true;
	}
}
void test8()
{
	for (int j = 0; j < 5; j++)
	{
		std::unique_lock<std::mutex> l(mu);
		if (!print)
		{
			cv.wait(l);
		}
		std::cout << "test8 j = " << j << std::endl;
		print = false;
	}
}

CRITICAL_SECTION section;//临界区变量
void test01()
{
	for (int i = 0; i < 5; i++)
	{
		EnterCriticalSection(&section);//类似于 mutex.lock() 
		std::cout << "this is test01 i = " << i << std::endl;
		Sleep(1);
		LeaveCriticalSection(&section);//类似于 mutex.unlock() 
	}
}
void test02()
{
	for (int j = 0; j < 5; j++)
	{
		EnterCriticalSection(&section);
		std::cout << "this is test02 j = " << j << std::endl;
		Sleep(1);
		LeaveCriticalSection(&section);
	}
}
HANDLE hmutex;
void test03()
{
	for (int i = 0; i < 5; i++)
	{
		WaitForSingleObject(hmutex, INFINITE);//类似于mutex.lock() 阻塞等待多少时间 
		std::cout << "test03 i = " << i << std::endl;
		ReleaseMutex(hmutex);//类似于mutex.unlock() 释放互斥锁 
	}
}
void test04()
{
	for (int j = 0; j < 5; j++)
	{
		WaitForSingleObject(hmutex, INFINITE);
		std::cout << "test04 j = " << j << std::endl;
		ReleaseMutex(hmutex);
	}
}
HANDLE hevent;
void test05()
{
	for (int i = 0; i < 5; i++)
	{
		WaitForSingleObject(hevent, INFINITE);//类似于mutex.lock() 阻塞等待多少时间 
		std::cout << "test05 i = " << i << std::endl;
		SetEvent(hevent);//类似于mutex.unlock() 释放互斥锁 
	}
}
void test06()
{
	for (int j = 0; j < 5; j++)
	{
		WaitForSingleObject(hevent, INFINITE);
		std::cout << "test06 j = " << j << std::endl;
		SetEvent(hevent);
	}
}
HANDLE sem;
void test07()
{
	for (int i = 0; i < 5; i++)
	{
		WaitForSingleObject(sem, INFINITE);//类似于mutex.lock() 阻塞等待多少时间 
		std::cout << "test07 i = " << i << std::endl;
		ReleaseSemaphore(sem, 1, NULL);//类似于mutex.unlock() 释放互斥锁 
	}
}
void test08()
{
	for (int j = 0; j < 5; j++)
	{
		WaitForSingleObject(sem, INFINITE);
		std::cout << "test08 j = " << j << std::endl;
		ReleaseSemaphore(sem, 1, NULL);
	}
}


int main(int argc, char const* argv[])
{
	int i = 0; 
	int rtn = 0;
	int ret = 0;
    char buff[100];


	char *tmp = int2hex(82);
	//read_csv2();//ok

	//float num = 0.3;
	//int result = ceil(num);
	//printf("向上取整后的结果是:%d\n", result);


	--------------多线程-----START------------------------
	//f_multi_thread();

	//f_multiThread();//【Demo1】:创建一个最简单的线程
	
	//f_multiThread2();//【Demo2】:在线程函数中传入参数
	
	//f_multiThread3();//【Demo3】:线程同步
	//售票系统 //
	//Test2();//【Demo4】:模拟火车售票系统


	====== C++11 线程库 ==== START ==========
	//std::thread a;//创建线程1,定义线程,后面再分配任务
	//a = std::thread(threadProc);
	//std::thread b(threadProc2, 5);//创建线程2 ,定义线程的时候分配任务,参数类似于printf一样,可以为多个
	//a.join();
	//b.join();//采用join,主线程会阻塞等待子线程执行完毕
	//std::thread c(threadProc3);
	//c.detach();//采用detach,主线程不会等,这个线程开启早,还能输出到主线程的控制台
	//std::cout << "main thread exit" << std::endl;
	//std::thread d(threadProc4);
	//d.detach();//

	//std::thread a(test1);
	//std::thread b(test2);
	//a.join();
	//b.join();
	//std::cout << "main thread finish." << std::endl;

	//std::thread a(test3);
	//std::thread b(test4);
	//a.join();
	//b.join();
	//std::cout << "main thread finish." << std::endl;

	//std::thread a(test5);
	//std::thread b(test6);
	//a.join();
	//b.join();

	//std::thread a(test7);
	//std::thread b(test8);
	//a.join();
	//b.join();
	====== C++11 线程库 ==== END ============

	====== W32API实现线程同步 ==== START ==========
	//InitializeCriticalSection(&section);//初始化临界区对象
	//std::thread a(test01);
	//std::thread b(test02);
	//a.join();
	//b.join();
	//DeleteCriticalSection(&section);//用完了,就删除临界区 

	//hmutex = CreateMutex(NULL, FALSE, "mutex");//创建一个互斥锁 
	//std::thread a(test03);
	//std::thread b(test04);
	//a.join();
	//b.join();
	//CloseHandle(hmutex);//释放句柄 

	//hevent = CreateEvent(NULL, FALSE, TRUE, "event");//创建一个事件 
	//std::thread a(test05);
	//std::thread b(test06);
	//a.join();
	//b.join();
	//CloseHandle(hevent);//释放句柄 

	sem = CreateSemaphore(NULL, 1, 2, "semaphore");
	std::thread a(test07);
	std::thread b(test08);
	a.join();
	b.join();
	CloseHandle(sem);//释放句柄 


	====== W32API实现线程同步 ==== END ============

	--------------多线程-----END--------------------------


	VS 与 Matlab 混合编程
	//rtn = f_VS_Matlab();


	system("pause");
    return 0;
}


//售票程序
DWORD WINAPI SaleTicket(LPVOID lpParameter)
{
	THD_DATA* pThreadData = (THD_DATA*)lpParameter;
	TICKET* pSaleData = pThreadData->pTicket;
	while (pSaleData->nCount > 0)
	{
		//请求获得一个互斥量锁
		WaitForSingleObject(g_hMutex2, INFINITE);
		if (pSaleData->nCount > 0)
		{
			std::cout << pThreadData->strThreadName << "出售第" << pSaleData->nCount-- << "的票,";
			if (pSaleData->nCount >= 0) 
			{
				std::cout << "出票成功!剩余" << pSaleData->nCount << "张票." << std::endl;
			}
			else 
			{
				std::cout << "出票失败!该票已售完。" << std::endl;
			}
		}
		Sleep(10);
		//释放互斥量锁
		ReleaseMutex(g_hMutex2);
	}

	return 0L;
}
//售票系统
void Test2()
{
	//创建一个互斥量
	g_hMutex2 = CreateMutex(NULL, FALSE, NULL);

	//初始化火车票
	TICKET ticket;
	ticket.nCount = 100;
	strcpy(ticket.strTicketName, "北京-->赣州");

	const int THREAD_NUMM = 2;//8;//
	THD_DATA threadSale[THREAD_NUMM];
	HANDLE hThread[THREAD_NUMM];
	for (int i = 0; i < THREAD_NUMM; ++i)
	{
		threadSale[i].pTicket = &ticket;
		std::string strThreadName = convertToString(i);

		strThreadName = "窗口" + strThreadName;

		strcpy(threadSale[i].strThreadName, strThreadName.c_str());

		//创建线程
		hThread[i] = CreateThread(NULL, NULL, SaleTicket, &threadSale[i], 0, NULL);

		//请求获得一个互斥量锁
		WaitForSingleObject(g_hMutex2, INFINITE);
		std::cout << threadSale[i].strThreadName << "开始出售 " << threadSale[i].pTicket->strTicketName << " 的票..." << std::endl;
		//释放互斥量锁
		ReleaseMutex(g_hMutex2);

		//关闭线程
		CloseHandle(hThread[i]);
	}

	system("pause");
}

参考:

【Linux】多线程同步的四种方式 - 西*风 - 博客园 (cnblogs.com)

一文搞定c++多线程同步机制_c++多线程同步等待-CSDN博客

C++多线程同步总结 - 念秋 - 博客园 (cnblogs.com)

Linux 下多线程(C语言) | 大眼睛男孩儿 (zhangxiaoya.github.io)

读写锁 - 张飘扬 - 博客园 (cnblogs.com)

Linux C++多线程同步的四种方式(非常详细)-CSDN博客

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

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

相关文章

java多线程相关概念

在Java多线程编程中&#xff0c;有几个关键的术语需要理解&#xff1a; 1.线程(Thread)&#xff1a;线程是操作系统能够进行运算调度的最小单位&#xff0c;它被包含在进程之中&#xff0c;是进程中的实际运作单位。 2.进程(Process)&#xff1a;进程是系统进行资源分配和调度…

下载NVIDIA官网的培训视频,生成中文字幕和PPT

下载NVIDIA官网的培训视频,生成中文字幕和PPT 一.[视频网站](https://www.nvidia.cn/on-demand/session/gtc24-s62129/)二.如何获取视频的原始链接三.下载视频的脚本【生成output.mp4】四.安装whisper环境【语音识别生成英文字幕】五.下载whisper模型六.生成英文字幕【输出merg…

“探索AIGC市场:腾讯元宝APP加入竞争,大模型产品的未来走向与个人选择“

文章目录 每日一句正能量前言使用体验分享独特优势和倾向选择字节豆包百度文心一言阿里通义千问腾讯元宝个人倾向选择结论 未来发展方向技术创新可持续可拓展性用户体验应用场景政府赋能数据安全与隐私保护伦理与社会责任国际合作与竞争结论 后记 每日一句正能量 不管现在有多么…

000-基于sklearn的机器学习入门:工作环境搭建与配置

本专栏将介绍基于Scikit-learn(简称sklearn)的机器学习入门知识。包括但不一定限于&#xff0c;机器学习基本知识、sklearn库简介&#xff0c;基于Sklearn库的机器学习实践。 这是本专栏的第000篇&#xff0c;将介绍如何安装和配置sklearn环境&#xff0c;不仅包括Sklearn库的…

【QT5】<知识点> IMX6ULL开发板运行QT

目录 1. 安装交叉编译器 2. 命令行交叉编译QT项目 3. 运行该可执行程序 4. 开发板上运行UDP程序与Ubuntu通信 1. 安装交叉编译器 第一步&#xff1a;进入正点原子论坛找到IMX6ULL开发板的资料&#xff0c;下载“开发工具”&#xff0c;将“交叉编译工具”中的fsl-imx-x11-…

Docker引起的漏洞问题

前言 测试环境上的中间件和java应用都是由docker进行部署的,但是因为docker的镜像访问有时候需要外网,由此引发了问题,在docker文件中 /usr/lib/systemd/system/docker.service 原有的配置为,可以看到进行了加密 ExecStart/usr/bin/dockerd --tlsverify --tlscacert/etc/docker…

【PL理论】(19) 函数式语言:更复杂的 let-in 示例 | 作用域 | 静态作用域 vs. 动态作用域

&#x1f4ad; 写在前面&#xff1a;本章我们将继续讲解函数式语言&#xff0c;介绍比上一章更复杂的 let-in 示例&#xff0c;进行分析。并讲解作用域&#xff0c;通过例子对比静态作用域和动态作用域的区别。 目录 0x00 复杂的 let-in 示例 0x01 作用域 0x02 静态作用域 v…

EI/CPCI/Scopus会议论文是啥?

EI/CPCI/Scopus会议论文是啥&#xff1f; EI/CPCI/Scopus是学术圈常见的字母缩写了&#xff0c;它们并非某一种期刊或是某一种杂志&#xff0c;而是一种便捷的论文检索工具。它们之间的区别在于&#xff0c;各自涵盖的领域的不同。▌EI &#xff08;The Engineering Index&…

STM32硬件接口I2C应用(基于MP6050)

目录 概述 1 STM32Cube控制配置I2C 1.1 I2C参数配置 1.2 使用STM32Cube产生工程 2 HAL库函数介绍 2.1 初始化函数 2.2 写数据函数 2.3 读数据函数 3 认识MP6050 3.1 MP6050功能介绍 3.2 加速计测量寄存器 ​编辑3.3 温度计量寄存器 3.4 陀螺仪测量寄存器 4 MP60…

openlayers 绘图功能,绘制多边形,draw组件的使用,一个简单的需求引发的思考(二)

上一篇是使用openlayers原生实现的&#xff0c;这一节使用vue3-openlayers实现(有轮子真好) 1 需求 使用openlayers绘图功能绘制多边形 2 分析 主要是openlayers中draw功能的使用 3 实现 为了方便&#xff0c;就不加载底图了&#xff0c;直接使用绘制功能 2.1 简单实现 …

ttkbootstrap的icon图标自定义

前言 在使用ttkbootstrap库时&#xff0c;发现icon参数使用报错&#xff0c;错误代码 root ttk.Window(themename"superhero",size(1400, 700),resizable(True, True),iconphoto"1.png" )结果报错&#xff1a;iconphoto path is bad; using default ima…

AC/DC电源模块的原理、特点以及其在实际应用中的重要性

BOSHIDA AC/DC电源模块的原理、特点以及其在实际应用中的重要性 AC/DC电源模块是一种用于将交流电转换为直流电的设备&#xff0c;广泛应用于各种电子设备中。这种电源模块可以有效地将电力从电网中提取出来&#xff0c;并将其转换为稳定的直流电源&#xff0c;供给各种不同功…

【短剧看剧系统之投流版】短剧看剧系统功能更新,前端uniapp搭建开发

目录 一、常规款短剧系统和投流版的区别&#xff1f; 二、后端体系 1.管理端&#xff1a; 2.代理投流端 三、功能区别 总结&#xff1a; 前言&#xff1a; 短剧看剧系统目前在抖音端是比较热门的&#xff0c;最重要的功能就是可以接入第三方cps&#xff0c;包含类目报白…

万众瞩目的苹果AI来了,但我们用不了

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 从今天开始&#xff0c;最了解你的不是你老婆&#xff0c;不是你自己&#xff0c;而是苹果AI。 万众瞩目的苹果WWDC24开发者大会在大半夜举办了&#xff0c;其中一项重要的更新是&#xff1a;苹果宣布要把ChatGPT集…

MES系统定制 | 生产调度车间排班计划/MES排程排产

MES系统是一种集成化的生产信息化管理系统&#xff0c;通过实时收集和分析车间生产数据&#xff0c;帮助企业实现生产过程的自动化控制和监测。它可以跟踪生产计划、设备状态、物料流动等关键指标&#xff0c;并提供实时报表和决策支持。在这个系统中&#xff0c;车间班次排班是…

零基础直接上手java跨平台桌面程序,使用javafx(五)TableView显示excel表

我们在窗口的中间加上TableVie&#xff1a; 在hello-view.fxml的文本中&#xff0c;要增加一些代码。在TableView定义中加上fx:id"TableView1"&#xff0c;这样java代码才方便访问&#xff0c;在java代码中要加上FXML private TableView TableView1;表示定义TableVie…

如何禁止使用U盘|禁止使用U盘的四个方法

你知道U盘滥用对企业的危害&#xff0c;总接下来有这三点: 数据泄露&#xff1a;U盘可以方便地存储和传输大量数据&#xff0c;但如果U盘丢失或被盗&#xff0c;其中的数据可能会被他人获取&#xff0c;从而导致数据泄露。病毒传播&#xff1a;U盘是病毒传播的常见途径之一。如…

基于若依的ruoyi-nbcio-plus里抄送人多页选择人员的bug修复

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; h…

点云技术在AI绘画中的革新性应用

引言&#xff1a; 随着人工智能的不断演进&#xff0c;艺术与科技的交融催生了AI绘画这一全新的创作方式。AI绘画不仅为艺术家提供了前所未有的工具&#xff0c;也拓展了艺术表达的边界。在这一进程中&#xff0c;点云技术作为一种重要的三维数据处理手段&#xff0c;其在AI绘画…

深入解析:常用的IP地址类型及其应用

随着互联网的日益发展&#xff0c;IP地址已经成为了我们日常生活中不可或缺的一部分。无论是浏览网页、发送邮件&#xff0c;还是进行在线视频通话&#xff0c;都离不开IP地址的参与。然而&#xff0c;对于许多非专业人士来说&#xff0c;IP地址的分类及其应用可能还是一个相对…