wxwidgets编写多线程程序--wxThread

2023-11-20

细节描述

线程基本上来说是应用程序中一条单独执行的路径。线程有时被称为轻量级进程,但线程与进程的根本不同之处在于不同进程存储空间是相互独立的,而同一进程里的所有线程共享同一地址空间。尽管这使得它更容易共享几个线程间的普通数据,但这也使得它有了另一个麻烦,即可能有多个线程同时访问一个变量,所以要小心的使用用于同步对象访问的变量,例如使用信号量(mutexes)和关键区域(critical sections)是被推荐的。另外,不要创建全局变量对象,因为在他们的构造函数里分配空间将会造成内存检查系统出现问题。

线程类型

wxWidgets有两种类型的线程:分离线程和联合线程,它们参考了POSIX 线程 API。这与win32API不同,其线程全部都是联合的。wxWidgets默认wxThreads为分离线程。分离线程一旦结束就会删除它们自己,不论是它们完成处理是自己完成删除还是通过调用Delete(),分离线程必须创建在堆上(例如通过new)。如果你想对你分配的分离线程上调用函数,你可以保存它们的实例(这句好像有问题啊,原文:Typically you'llwant to store the instances of the detached wxThreads you allocate, so that youcan call functions on them.)。因为它们的特性所致,你每次访问它们都必须使用关键区域。

 

//声明一个新的事件种类用于我们的MyThread类
wxDECLARE_EVENT(wxEVT_COMMAND_MYTHREAD_COMPLETED, wxThreadEvent);
wxDECLARE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent);

wxDEFINE_EVENT(wxEVT_COMMAND_MYTHREAD_COMPLETED, wxThreadEvent);//定义事件种类
wxDEFINE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent);


class MyFrame;//前置声明

class MyThread : public wxThread
{
public:
	MyThread(MyFrame *handler)
        	: wxThread(wxTHREAD_DETACHED)
        { 
		m_pHandler = handler 
	}
	
	~MyThread();
protected:
	virtual ExitCode Entry();
	MyFrame *m_pHandler;
};

class MyFrame : public wxFrame
{
public:
	...
	~MyFrame()
	{
	//任何对线程的清理相对于在析构函数来说最好在事件处理函数OnClose()中进行。
	//这是因为顶层窗口的事件循环在调用它的析构函数处不会激活,如果在窗口析构时线程发送事件,
	//这些事件不会被处理除非你在OnClose结束线程
	}
	...
	void DoStartThread();
	void DoPauseThread();
	//线程恢复和DoPauseThread()非常相似

	void DoResumeThread() { ... }

	void OnThreadUpdate(wxThreadEvent&);
	void OnThreadCompletion(wxThreadEvent&);
	void OnClose(wxCloseEvent&);
protected:
	MyThread *m_pThread;
	wxCriticalSection m_pThreadCS; // 保护m_pThread指针
	friend class MyThread; //友元函数,允许访问我们的线程m_pThread
	wxDECLARE_EVENT_TABLE();
};

wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_CLOSE(MyFrame::OnClose)
EVT_MENU(Minimal_Start, MyFrame::DoStartThread)
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_UPDATE, MyFrame::OnThreadUpdate)
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_COMPLETED, MyFrame::OnThreadCompletion)
wxEND_EVENT_TABLE()


void MyFrame::DoStartThread()
{
	m_pThread = new MyThread(this);
	if ( m_pThread->Run() != wxTHREAD_NO_ERROR )
	{
		wxLogError("Can't create the thread!");
		delete m_pThread;
		m_pThread = NULL;
	}
	//在调用wxThread::Run()之后,指针m_pThread是不安全的:
	//在任何时候线程都有可能结束(因为它完成了自己的工作)
	//为了避免调用无效的指针,在线程结束时OnThreadExit()中将会把指针赋值为空。
}
wxThread::ExitCode MyThread::Entry()
{
	while (!TestDestroy())
	{
		// ... 干一些事情...
		wxQueueEvent(m_pHandler, new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_UPDATE));//发送事件
	}

	//通知事件句柄这个线程将会被销毁。注意:这里我们假定使用m_pHandler是安全的
	//(在这种情况下这将由MyFrame的析构函数确保)
	wxQueueEvent(m_pHandler, new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_COMPLETED));//发送事件
	return (wxThread::ExitCode)0; // 成功
}

MyThread::~MyThread()
{
	wxCriticalSectionLocker enter(m_pHandler->m_pThreadCS);
	//线程正在被销毁,确保不要调用了无效的指针
	m_pHandler->m_pThread = NULL;
}

void MyFrame::OnThreadCompletion(wxThreadEvent&)
{
	wxMessageOutputDebug().Printf("MYFRAME: MyThread exited!\n");
}

void MyFrame::OnThreadUpdate(wxThreadEvent&)
{
	wxMessageOutputDebug().Printf("MYFRAME: MyThread update...\n");
}

void MyFrame::DoPauseThread()
{

	//任何时候我们访问m_pThread时必须先确认在此期间它不会被修改;由于一个单独线程在给出时位于一个
	//安全区域,所以下面的代码是安全的。
	wxCriticalSectionLocker enter(m_pThreadCS);
	if (m_pThread) // 线程仍旧存在?
	{
	//不在安全区域,一旦到达这里,下列情况可能会发生:系统调度把控制权给MyThread::Entry(),
	//而这时候线程可能会因为完成了处理而使指针无效

	if (m_pThread->Pause() != wxTHREAD_NO_ERROR )

	wxLogError("Can't pause the thread!");
	}
}

void MyFrame::OnClose(wxCloseEvent&)
{
	{
		wxCriticalSectionLocker enter(m_pThreadCS);
		if (m_pThread) // 线程仍旧存在?
			{
				wxMessageOutputDebug().Printf("MYFRAME: deleting thread");
				if (m_pThread->Delete() != wxTHREAD_NO_ERROR )
				wxLogError("Can't delete the thread!");
			}
	}
	//离开安全区域来给线程进入析构函数的可能(安全区域保护m_pThreadCS)
	while (1)
	{
		{ // 析构函数执行了吗?
		wxCriticalSectionLocker enter(m_pThreadCS);
		if (!m_pThread) break;
		}
		// wait for thread completion
		wxThread::This()->Sleep(1);
	}
	Destroy();
}

 

 

 

相反的,联合线程不会自我删除当他们完成处理,它可以安全创建在栈上。联合线程同样提供了通过Wait()来获得Entry()返回值的功能。你不需要急着把所有的线程都创建为联合线程,因为它们也拥有不利之处:你必须使用Wait()函数来给联合线程释放资源,不然它占用的系统资源不会被释放,而且你必须手动的正确的删除线程对象如果你没在栈上创建它。相反的,分离线程是“点火即忘”:你只需要开始分离线程,当它完成处理,它会自动停止并销毁它自己

线程删除

不管它是否已经停止,你都应该在联合线程调用Wait()来释放内存,就像前面线程种类里说的那样。如果你在堆上创建了一个线程,记得手动删除它们使用delete操作或类似的只有分离线程处理这种内存管理类型(后半句好奇怪,原文:If you created ajoinable thread on the heap, remember to delete it manually with thedelete operator or similar means as onlydetached threads handle this type of memory management.)

因为分离线程完成处理会自我删除,你要小心在其上调用程序。如果你确定线程正在运行,并想结束它,你可以优雅的调用来Delete()结束他(这意味着线程会在调用Delete()后删除掉)。这意味着你永远都不应该尝试使用delete或相似的操作来删除分离线程。

就像是上面提到的,Wait()Delete()都分别尝试优雅的删除分离与联合线程。它们通过等待直到线程调用TestDestroy()或结束处理(例如从wxThread::Entry返回)

(这句也有问题,原文:They do this by waiting until the thread in questioncallsTestDestroy() or endsprocessing)

明显的,如果线程已经调用TestDestroy()并且没有结束,调用Wait()Delete()的线程将会停止。这就是为什么要在你的线程的Entry()尽可能频繁的调用TestDestroy()并在它返回true时立即结束。

万不得已你可以使用Kill()立即结束线程。这种方式极度不推荐你用,因为这样并不能释放与对象相联系的资源(尽管分离线程的线程对象仍会被删除)并会是c运行库处于不安全状态。

 第二线程调用绘图wxwidgets

 

除了“主程序线程”(运行wxApp:OnInit()或主函数运行的一个函数)之外的所有线程都被认为是“二级线程”。

GUI调用,例如对wxWindow或wxBitmap的调用,在二级线程中是不安全的,可能会过早结束你的应用程序。这是由于好几个原因:包括底层的nativeAPI,类似于其他api如MFC一样,wxThread不在二级线程运行aGUI事件循环。

工作区的一些wxWidgets端口会在任何GUI调用前调用 wxMutexGUIEnter() ,然后调用wxMutexGUILeave()。但是,推荐的方法是通过wxQueueEvent()发送的事件,在主线程中简单地处理GUI调用。但这并不代表调用这些类是线程安全的,包括 wxString在内许多类都不是线程安全的。

 不要轮询wxThread

用户使用wxThread的一个普遍问题是在主线程它们会每次调用IsRunning()检查线程看他们是否已经结束,结果发现它们的应用程序出现问题了,因为线程是默认的分离线程而且线程已经自我删除。自然的,它们会尝试使用联合线程来取代前面的分离特性。然而,轮询一个来看他们是否已结束通常来说不是个好主意—实际上,如果可能,任何对正在运行的线程调用的函数都应该避免。相反的,当线程已经结束寻找一种方法来通知你自己。

通常你只需要通知主线程,在这种情况你可以通过wxQueueEvent()来发送事件给他。第二线程的情况时,如有必要,你可以调用别的类的程序当线程:完成处理、使用信号量对变量赋值、别的同步操作

测试图:

运行时

使用Delete()函数删除线程

我现在感觉联合线程应当是用于当另一线程需要等待联合线程完成某项任务时再运行,这时就可以在联合线程周期调用TestDesdory()而等待线程调用联合线程的wait(),这样就可以避免等待线程白白消耗资源。而分离线程就是自己运行完自己删除,如果需要和别的线程通信还可以用事件通知。

用于线程同步的对象

1.wxMutex--互斥量

 

wxMutexError  Lock ()
锁定互斥对象,相当于参数为infinite的LockTimeout() 函数。
注意:若此互斥量早已被调用线程锁定,则函数不会阻塞而会立即返回

 

wxMutexError  LockTimeout (unsigned long msec)
尝试锁定互斥量,在特定时间周期内
wxMutexError  TryLock ()
  尝试锁定互斥量,若不能锁定,函数会立即返回,并且返回 wxMUTEX_BUSY错误
 
wxMutexError  Unlock ()
  解锁互斥量

wxMutexLocker

wxmutex的辅助函数,构造函数中以一个互斥量为参数,他将在析构函数中解锁互斥量,这使得互斥量的解锁更加可靠,即使忘记解锁也不会造成死锁。

bool wxMutexLocker::IsOk()const

若取得互斥量所有权,返回true,否则返回false.

2.wxCriticalSection--关键区域

 

void  Enter ()
  进入关键区域,如果早已经有别的线程进入,则本次调用将会被阻塞,直到那个线程调用了 Leave().
注意:如果一个线程多次进入关键区域,这并不会导致死锁,事实上在这种情况下函数会立刻返回。
 
bool  TryEnter ()
  尝试进入关键区域,如果不能进入,它会立即返回false。
 
void  Leave ()
  离开关键区域使得其他线程得以访问被他保护的全局数据。

wxCriticalSectionLocker,作用类似wxMutexLocker

 

3.wxCondition--条件变量

 

 

wxCondError  Broadcast ()
  通知所有线程,把他们都唤醒
注意:这个函数可能会被调用,无论与之相关联的互斥量是否为锁定状态,
 
bool  IsOk () const
  若对象早已被成功初始化则返回true,若有错误发生返回false
 
wxCondError  Signal ()
  唤醒最多一个对象。
若多个线程等待同一条件变量,确切的被唤醒线程是未定义的。若无线程在等待,这次信号将会丢失,而条件变量必须再次发信号,以唤醒那些稍后可能会开始等待的线程。
注意:这个函数可能会被调用,无论与之相关联的互斥量是否为锁定状态
 
wxCondError  Wait ()
  等待直到条件变量激发。此方法将会自动解锁与条件变量相关联的互斥量的锁。然后使线程进入睡眠状态直到Signal()Broadcast()被调用,它会再次锁定互斥量然后返回。
注意:即使Signal()Wait()之前已经被调用,且没有唤醒任何线程,线程仍旧会继续等待下一个信号,所以确保Signal()Wait()之后调用是很重要的,不然线程也许将一直睡眠下去
 
template<typename Functor >
wxCondError  Wait (const Functor &predicate)
  等待直到条件变量发出信号,且与之关联的条件为真。这是一个方便的重载用来忽略假的唤醒当等待特定条件变为true时。
这个函数相当于:

while ( !predicate() )

{

wxCondError e =Wait();

if ( e != wxCOND_NO_ERROR )

return e;

}

return wxCOND_NO_ERROR;

 
wxCondError  WaitTimeout (unsigned long milliseconds)
  等待直到条件被激发或超时时间到达。

 

4.wxSemaphore--信号量

 

 

wxSemaphore是一个计数器,用于限制并发访问共享资源的线程数。

该计数器始终在0和创建信号量期间指定的最大值之间。当计数器严格大于0时,调用wxSemaphore :: Wait()将立即返回并递减计数器。一旦达到0,任何后续的对wxSemaphore :: Wait的调用,只有当信号量计数器再次变为严格的正值时,才会返回,因为调用wxSemaphore :: Post会增加计数器的结果。

一般来说,信号量对于限制只能同时被某些固定数量的客户端访问的共享资源的访问是有用的。例如,当建模酒店预订系统时,可以创建一个具有等于可用房间总数的计数器的信号量。每次保留一个房间时,通过调用wxSemaphore :: Wait来获取信号量,并且每次释放房间时,都应该通过调用wxSemaphore :: Post来释放信号量。

 

wxSemaError  Post ()
  增加信号量计数值并通知等待的线程里面的一个
 
wxSemaError  TryWait ()
  Wait()相似,但他会立即返回
 
wxSemaError  Wait ()
  无限等待直到信号量计数值变为正值,稍后会减一并返回
 
wxSemaError  WaitTimeout (unsigned long timeout_millis)
  Wait()相似,但有超时限制

 

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

wxwidgets编写多线程程序--wxThread 的相关文章

  • C++-std::unique_lock介绍和简单使用

    unique lock std unique lock比std lock guard更灵活 这种灵活性主要体现在以下几点 lock guard在构造时或者构造前 std adopt lock 就已经获取互斥锁 并且在作用域内保持获取锁的状态
  • Jmeter动态吞吐量实现

    在容量测试时 控量 是非常重要的 JMeter 是根据线程数大小来控制压力强弱的 但我们制定的压测目标中的指标往往是吞吐量 QPS TPS 这就给测试人员带来了不便之处 必须一边调整线程数 一边观察 QPS TPS 达到什么量级了 为了解决
  • 55黑马QT笔记之关闭子线程

    55黑马QT笔记之关闭子线程 1 这里为什么要单独写多一篇文章来说线程的关闭呢 主要是想让大家提升印象 养成资源回收的好习惯 任何时候都要想起开辟过的内存回收 这里的关闭子线程上一篇也写到了 就是利用关闭窗口时调用槽函数回收掉 2 具体步骤
  • JAVA并发:线程安全与Synchorinzed

    1 什么是线程安全问题 线程的合理使用能够提升程序的处理性能 主要有两个方面 第一个是能够利用多核 cpu 以及超线程技术来实现线程的并行执行 第二个是线程的异步化执行相比于同步执行来说 异步执行能够很好的优化程序的处理性能提升并发吞吐量
  • wxPython:BoxSizer中的项目不水平扩展,仅垂直扩展

    我有几个不同大小的按钮 它们按照我想要的方式扩展 但是 当我将父级添加到新的 wx BoxSizer 用于在框架中的所有元素周围添加边框 时 已添加的 sizer 可以在垂直方向上正确运行 但不能在水平方向上运行 下面的代码演示了这个问题
  • 当虚拟不起作用时

    目前我的 C 类中有一个奇怪的错误 我有一个 ActiveX 包装类 作为 wxWidgets 的一部分 我向其中添加了一个新的虚拟函数 我有另一个类继承自 ActiveX 类 wxIEHtmlWin 但是 ActiveX 类总是调用它自己
  • 在 wxPython 应用程序中实现我自己的事件循环

    我正在编写一个 wxPython 应用程序 它将进行大量的数据分析和显示 到目前为止 当两个线程尝试同时更改 GUI 中的某些内容时 我编写的方式会导致出现问题 我想做的是建立自己的在主线程上运行的简单队列这样我就可以确保 UI 更新一次发
  • 如何确定给定 wxWidgets 中当前字体的字符串的大小

    有没有办法根据 C wxWidgets中当前选择的字体确定给定字符串的显示长度 以像素为单位 例如 如果我打印出字符串 Speed 并希望在 和后面的值之间放置 10 个像素 我需要知道 Speed 字符串有多长 有没有办法确定这一点 我似
  • 字体大小缩放问题

    我正在编写一个 C wxWidgets 计算器应用程序 我希望 wxTextCtrl 的字体和自定义按钮在调整窗口大小时能够缩放 问题是 我的按钮中的文本并不总是精确地位于中心 但有时会稍微偏离 特别是在绿色和红色按钮中 当我最大化窗口时
  • wxPython 带有面板的框架的最小尺寸

    wxpython 2 8 11 0 python 2 7 如果我放一些Sizer一些控件直接进入Frame like import wx app wx App frm wx Frame None title title sizer wx B
  • 多线程编程与性能优化

    引言 在上一篇的入门篇中 我们对Android线程的基础概念和多线程编程模型有了初步了解 本篇将深入探讨多线程编程技术和性能优化策略 以提升应用的效率和响应性 高级多线程编程技术 使用线程池管理线程 线程池是一组预先创建的线程 用于执行任务
  • TaskDecatator用法

    在Spring框架中 TaskDecorator 是一个接口 它可以用来自定义由 ThreadPoolTaskExecutor 或其他任务执行器管理的任务的装饰行为 这通常用于在执行任务之前和之后添加某些上下文相关的行为 比如设置线程上下文
  • wxHaskell标签无法显示全文

    我正在 Windows XP 上使用 Hello World 测试 wxHaskell http www haskell org haskellwiki WxHaskell Quick start http www haskell org
  • wxWidgets运行时错误(版本不匹配)

    我在启动程序时遇到问题 致命错误 检测到程序和库构建版本之间不匹配 该库使用3 0 wchar t C ABI 1010编译器 wx容器 兼容2 8 并且您的程序使用3 0 wchar t 使用C ABI 1009的编译器 wx容器 与2
  • 我如何使用 wxwidgets 在 C++ 中访问串行端口数据

    我是电子与通信工程专业的学生 我正在开发一个项目 其中微控制器将数据发送到计算机的串行端口 异步 我目前正在为我的 GUI 工作学习 wxWidgets 我的问题 是否可以使用wxWidgets来获取数据并显示 实施起来是不是非常困难呢 我
  • 如何在wxpython中的StaticBitmap上创建悬停效果?

    我想在 StaticBitmap 上创建悬停效果 如果鼠标光标位于位图上 则显示一张图像 如果没有 则显示第二张图像 这是一个简单的程序 与按钮完美配合 但是 StaticBitmap 不会发出 EVT WINDOW ENTER EVT W
  • 在 Linux 上创建带范围的 wxSlider

    我正在尝试使用 Python 中的 wxSlider 创建一个带有范围选择选项的滑块 它有一个可选的范围参数 但问题是 SL SELRANGE 允许用户在滑块上选择范围 仅限 Windows 我正在使用Linux 我想我可以继承 wxSli
  • wxPython 最好的实时绘图小部件是什么?

    我想使用 Python 和 wxPython 显示一个包含一条或两条曲线 每秒最多 50 个样本的实时图表 该小部件应支持 Win32 和 Linux 平台 欢迎任何提示 编辑添加 我不需要以 50 fps 更新显示 但需要在两条曲线上显示
  • wxWidgets - 事件表与 Connect()?

    我刚刚开始使用 C 学习 wxWidgets 3 0 版 我已经注意到 wxWidgets 中的事件处理是由事件表完成的 但一篇教程也提到了 Connect 实际上它只是说 本教程将使用事件表 而不是 Connect 我想知道事件表和 Co
  • CMake 在 Windows 上找不到 wxWidgets

    我的 CMakeLists txt 中有以下代码片段 如中所述wxWidgets 维基 https wiki wxwidgets org CMake set wxWidgets ROOT DIR libs wxWidgets set wxW

随机推荐

  • Log4j2漏洞修复

    一 漏洞说明 Apache Log4j2是一个基于Java的日志记录工具 由于Apache Log4j2某些功能存在递归解析功能 攻击者可直接构造恶意请求 触发远程代码执行漏洞 漏洞利用无需特殊配置 经阿里云安全团队验证 Apache St
  • npm安装卸载命令

    npm安装卸载命令 npm安装模块 npm 安装 npm install xxx 利用 npm 安装xxx模块到当前命令行所在目录 npm install xxx 安装但不写入package json npm install g xxx 利
  • CM4 启用UART3~6

    vim boot config txt dtoverlay uart0 dtoverlay uart3 txd3 pin 4 rxd3 pin 5 dtoverlay uart4 txd4 pin 8 rxd4 pin 9 dtoverla
  • mongodb学习笔记

    MongoDB 1 下载安装 1 1 下载MongoDB 这里我推介下载zip版本 解压到任意盘 由于C盘容易满 所以我放到了D盘 我在D盘创建了一个 mongoDB 的目录 并将压缩包解压到了这个目录里面 下载地址 https www m
  • [当人工智能遇上安全] 8.基于API序列和机器学习的恶意家族分类实例详解

    您或许知道 作者后续分享网络安全的文章会越来越少 但如果您想学习人工智能和安全结合的应用 您就有福利了 作者将重新打造一个 当人工智能遇上安全 系列博客 详细介绍人工智能与安全相关的论文 实践 并分享各种案例 涉及恶意代码检测 恶意请求识别
  • Unity中实现倒计时的几种方式

    1 Time time using UnityEngine public class TimeTest MonoBehaviour public float secound 10 void Update Timing private flo
  • 新闻文本分类—基于深度学习的文本分类2

    学习目标 学习Word2Vec的使用和基础原理 学习使用TextCNN TextRNN进行文本表示 学习使用HAN网络结构完成文本分类 文本表示方法 Part3 词向量 本节通过word2vec学习词向量 word2vec模型背后的基本思想
  • 细谈JavaWeb中的Request和Response

    文章目录 1 Request和Response的概述 2 Request对象 2 1 Request继承体系 2 2 Request获取请求数据 2 2 1 获取请求行数据 2 2 2 获取请求头数据 2 2 3 获取请求体数据 2 2 4
  • 2020最新版KVM虚拟机安装详解

    VMware Workstation Pro15 5下 1 操作环境 CentOS Linux release 7 7 1908 Core 2 需要用到的工具 XSHELL Centos任意版本镜像 3 必须安装的软件 Xmanager p
  • ec6110刷linux系统,华为DIIEC6110M_VER_C主板救砖纯净系统烧录固件包下载

    大家好今天小编跟大家分享关于华为DIIEC6110M VER C主板 强制升级 但是无反应强刷不起作用或短接后只亮一个绿灯 由于盒子厂商系统升级后 屏蔽了强刷模式导致无法使用 短接方式进行强刷 此时短接强刷这条路行不通的时候 需要使用线刷进
  • 2023年4月23日--4月30日(pbr为主,有时间就看看Ue视频教程,50小时,合计2039小时,剩余7961小时)

    按照规划 本周结合工作内容 以Pbr为主 可以从Ue的材质编辑器获取材质参数 写到glsl或者filament引擎 目前 ue视频教程进行到了智 慧 城 市 3 13 mysql 7 1 tf1 4 11 蓝图反射 1 9 moba 1 5
  • mysql 索引类型详解

    索引的类型和存储引擎有关 每种存储引擎所支持的索引类型不一定完全相同 MySQL 索引可以从存储方式 逻辑角度和实际使用的角度来进行分类 存储方式区分 根据存储方式的不同 MySQL 中常用的索引在物理上分为 B 树索引和 HASH 索引两
  • Downie 4 4.6.12 MAC上最好的一款视频下载工具

    Downie for Mac 简介 Downie是Mac下一个简单的下载管理器 可以让您快速将不同的视频网站上的视频下载并保存到电脑磁盘里然后使用您的默认媒体播放器观看它们 Downie 4 Downie 4 for Mac Downie
  • 编写代码常用快捷键

    编写代码常用快捷键 shift 或 逐个选中字符 ctrl 或 逐词移动光标 ctrl shift 或 逐词选中字符 常用 Home键 将光标移动到行开头 End键 将光标移动到到行结尾 常用 配合shift 或 Shift Home 从光
  • 华为云,站在数字化背后

    一场新的中国数字化战斗 正在被缓缓拉开帷幕 作者 裴一多 出品 产业家 如果说最近的讨论热点是什么 那无疑是互联网云 在数字化进入纵深的当下 一种市面上的观点是互联网的云业务由于盈利等问题 正在成为 被抛弃 的一方 互联网公司开始重新回归T
  • Spyder入门使用教程

    Spyder入门使用教程 Spyder汉化 Spyder汉化博客 创建项目 首先介绍Spyder布局 主要分上面的功能栏和下方的三个区块 点击创建新的项目 选择项目存放的目录 输入项目名 完成项目创建 创建新的文件 按Ctrl S 保存文件
  • Docker 资源汇总

    Docker 资源汇总 转载来源 http codecloud net docker resource 6090 html Menu Main Resources Books Websites Documents Archives Comm
  • Anaconda配置

    Anaconda配置 创建环境 conda create n 环境名 python 3 8 移除环境 conda remove n 环境名 all 查看所有环境 conda env list 激活环境 conda activate 环境名
  • 华为OD机试 - 组装最大可靠性设备(Java )

    题目描述 一个设备由N种类型元器件组成 每种类型元器件只需要一个 类型type编号从0 N 1 每个元器件均有可靠性属性reliability 可靠性越高的器件其价格price越贵 而设备的可靠性由组成设备的所有器件中可靠性最低的器件决定
  • wxwidgets编写多线程程序--wxThread

    细节描述 线程基本上来说是应用程序中一条单独执行的路径 线程有时被称为轻量级进程 但线程与进程的根本不同之处在于不同进程存储空间是相互独立的 而同一进程里的所有线程共享同一地址空间 尽管这使得它更容易共享几个线程间的普通数据 但这也使得它有