MFC多线程编程之一——问题提出

2023-11-19

原文地址:http://www.vckbase.com/document/viewdoc/?id=1704

一、问题的提出

编写一个耗时的单线程程序:

  新建一个基于对话框的应用程序SingleThread,在主对话框IDD_SINGLETHREAD_DIALOG添加一个按钮,ID为IDC_SLEEP_SIX_SECOND,标题为“延时6秒”,添加按钮的响应函数,代码如下:

void CSingleThreadDlg::OnSleepSixSecond() 
{
	Sleep(6000); //延时6秒
}
  编译并运行应用程序,单击“延时6秒”按钮,你就会发现在这6秒期间程序就象“死机”一样,不在响应其它消息。为了更好地处理这种耗时的操作,我们有必要学习——多线程编程。

二、多线程概述

  进程和线程都是操作系统的概念。进程是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它各种系统资源组成,进程在运行过程中创建的资源随着进程的终止而被销毁,所使用的系统资源在进程终止时被释放或关闭。
  线程是进程内部的一个执行单元。系统创建好进程后,实际上就启动执行了该进程的主执行线程,主执行线程以函数地址形式,比如说main或WinMain函数,将程序的启动点提供给Windows系统。主执行线程终止了,进程也就随之终止。
  每一个进程至少有一个主执行线程,它无需由用户去主动创建,是由系统自动创建的。用户根据需要在应用程序中创建其它线程,多个线程并发地运行于同一个进程中。一个进程中的所有线程都在该进程的虚拟地址空间中,共同使用这些虚拟地址空间、全局变量和系统资源,所以线程间的通讯非常方便,多线程技术的应用也较为广泛。
  多线程可以实现并行处理,避免了某项任务长时间占用CPU时间。要说明的一点是,目前大多数的计算机都是单处理器(CPU)的,为了运行所有这些线程,操作系统为每个独立线程安排一些CPU时间,操作系统以轮换方式向线程提供时间片,这就给人一种假象,好象这些线程都在同时运行。由此可见,如果两个非常活跃的线程为了抢夺对CPU的控制权,在线程切换时会消耗很多的CPU资源,反而会降低系统的性能。这一点在多线程编程时应该注意。
  Win32 SDK函数支持进行多线程的程序设计,并提供了操作系统原理中的各种同步、互斥和临界区等操作。Visual C++ 6.0中,使用MFC类库也实现了多线程的程序设计,使得多线程编程更加方便。

三、Win32 API对多线程编程的支持

  Win32 提供了一系列的API函数来完成线程的创建、挂起、恢复、终结以及通信等工作。下面将选取其中的一些重要函数进行说明。

1、HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
                 DWORD dwStackSize,
                 LPTHREAD_START_ROUTINE lpStartAddress,
                 LPVOID lpParameter,
                 DWORD dwCreationFlags,
                 LPDWORD lpThreadId);
该函数在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄,其中各参数说明如下:
  • lpThreadAttributes:指向一个 SECURITY_ATTRIBUTES 结构的指针,该结构决定了线程的安全属性,一般置为 NULL;
  • dwStackSize:指定了线程的堆栈深度,一般都设置为0;
  • lpStartAddress:表示新线程开始执行时代码所在函数的地址,即线程的起始地址。一般情况为(LPTHREAD_START_ROUTINE)ThreadFunc,ThreadFunc 是线程函数名;
  • lpParameter:指定了线程执行时传送给线程的32位参数,即线程函数的参数;
  • dwCreationFlags:控制线程创建的附加标志,可以取两种值。如果该参数为0,线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该线程处于挂起状态,并不马上执行,直至函数ResumeThread被调用;
  • lpThreadId:该参数返回所创建线程的ID;

如果创建成功则返回线程的句柄,否则返回NULL。

2、DWORD SuspendThread(HANDLE hThread);
该函数用于挂起指定的线程,如果函数执行成功,则线程的执行被终止。
3、DWORD ResumeThread(HANDLE hThread);
该函数用于结束线程的挂起状态,执行线程。
4、VOID ExitThread(DWORD dwExitCode);
该函数用于线程终结自身的执行,主要在线程的执行函数中被调用。其中参数dwExitCode用来设置线程的退出码。
5、BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);
  一般情况下,线程运行结束之后,线程函数正常返回,但是应用程序可以调用TerminateThread强行终止某一线程的执行。各参数含义如下:
  • hThread:将被终结的线程的句柄;
  • dwExitCode:用于指定线程的退出码。

  使用TerminateThread()终止某个线程的执行是不安全的,可能会引起系统不稳定;虽然该函数立即终止线程的执行,但并不释放线程所占用的资源。因此,一般不建议使用该函数。

6、BOOL PostThreadMessage(DWORD idThread,
			UINT Msg,
			WPARAM wParam,
			LPARAM lParam);
该函数将一条消息放入到指定线程的消息队列中,并且不等到消息被该线程处理时便返回。
  • idThread:将接收消息的线程的ID;
  • Msg:指定用来发送的消息;
  • wParam:同消息有关的字参数;
  • lParam:同消息有关的长参数;

调用该函数时,如果即将接收消息的线程没有创建消息循环,则该函数执行失败。

四、Win32 API多线程编程例程

例程1 MultiThread1

  1. 建立一个基于对话框的工程MultiThread1,在对话框IDD_MULTITHREAD1_DIALOG中加入两个按钮和一个编辑框,两个按钮的ID分别是IDC_START,IDC_STOP ,标题分别为“启动”,“停止”,IDC_STOP的属性选中Disabled;编辑框的ID为IDC_TIME ,属性选中Read-only;
     
  2. 在MultiThread1Dlg.h文件中添加线程函数声明:
    void ThreadFunc();
    
    注意,线程函数的声明应在类CMultiThread1Dlg的外部。 在类CMultiThread1Dlg内部添加protected型变量:
    	HANDLE hThread;
    	DWORD ThreadID;
    
    分别代表线程的句柄和ID。 
     
  3. 在MultiThread1Dlg.cpp文件中添加全局变量m_bRun :
    volatile BOOL m_bRun;
    
    m_bRun 代表线程是否正在运行。

    你要留意到全局变量 m_bRun 是使用 volatile 修饰符的,volatile 修饰符的作用是告诉编译器无需对该变量作任何的优化,即无需将它放到一个寄存器中,并且该值可被外部改变。对于多线程引用的全局变量来说,volatile 是一个非常重要的修饰符。

    编写线程函数:
    void ThreadFunc()
    {
    	CTime time;
    	CString strTime;
    	m_bRun=TRUE;
    	while(m_bRun)
    	{
    		time=CTime::GetCurrentTime();
    		strTime=time.Format("%H:%M:%S");
    		::SetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_TIME,strTime);
    		Sleep(1000);
    	}
    }
    
    该线程函数没有参数,也不返回函数值。只要m_bRun为TRUE,线程一直运行。

    双击IDC_START按钮,完成该按钮的消息函数:
    void CMultiThread1Dlg::OnStart() 
    {
    	// TODO: Add your control notification handler code here
    	hThread=CreateThread(NULL,
    		0,
    		(LPTHREAD_START_ROUTINE)ThreadFunc,
    		NULL,
    		0,
    		&ThreadID);
    	GetDlgItem(IDC_START)->EnableWindow(FALSE);
    	GetDlgItem(IDC_STOP)->EnableWindow(TRUE);
    
    }
    
    双击IDC_STOP按钮,完成该按钮的消息函数:
    void CMultiThread1Dlg::OnStop() 
    {
    	// TODO: Add your control notification handler code here
    	m_bRun=FALSE;
    	GetDlgItem(IDC_START)->EnableWindow(TRUE);
    	GetDlgItem(IDC_STOP)->EnableWindow(FALSE);
    }
    
    编译并运行该例程,体会使用Win32 API编写的多线程。

例程2 MultiThread2

  该线程演示了如何传送一个一个整型的参数到一个线程中,以及如何等待一个线程完成处理。

  1. 建立一个基于对话框的工程MultiThread2,在对话框IDD_MULTITHREAD2_DIALOG中加入一个编辑框和一个按钮,ID分别是IDC_COUNT,IDC_START ,按钮控件的标题为“开始”;
  2. 在MultiThread2Dlg.h文件中添加线程函数声明:
    void ThreadFunc(int integer);
    
    注意,线程函数的声明应在类CMultiThread2Dlg的外部。

    在类CMultiThread2Dlg内部添加protected型变量:
    	HANDLE hThread;
    	DWORD ThreadID;
    
    分别代表线程的句柄和ID。
     
  3. 打开ClassWizard,为编辑框IDC_COUNT添加int型变量m_nCount。 在MultiThread2Dlg.cpp文件中添加:
    void ThreadFunc(int integer)
    {
    	int i;
    	for(i=0;i<integer;i++)
    	{
    		Beep(200,50);
    		Sleep(1000);
    	}
    } 
    
    双击IDC_START按钮,完成该按钮的消息函数:
    void CMultiThread2Dlg::OnStart() 
    {
    	UpdateData(TRUE);
    	int integer=m_nCount;
    	hThread=CreateThread(NULL,
    		0,
    		(LPTHREAD_START_ROUTINE)ThreadFunc,
    		(VOID*)integer,
    		0,
    		&ThreadID);
    	GetDlgItem(IDC_START)->EnableWindow(FALSE);
    	WaitForSingleObject(hThread,INFINITE);
    	GetDlgItem(IDC_START)->EnableWindow(TRUE);
    }
    
    顺便说一下WaitForSingleObject函数,其函数原型为:
    DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);
    
    • hHandle为要监视的对象(一般为同步对象,也可以是线程)的句柄;
    • dwMilliseconds为hHandle对象所设置的超时值,单位为毫秒;

      当在某一线程中调用该函数时,线程暂时挂起,系统监视hHandle所指向的对象的状态。如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。参数dwMilliseconds有两个具有特殊意义的值:0和INFINITE。若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。
      本例程调用该函数的作用是按下IDC_START按钮后,一直等到线程返回,再恢复IDC_START按钮正常状态。 编译运行该例程并细心体会。

例程3 MultiThread3

传送一个结构体给一个线程函数也是可能的,可以通过传送一个指向结构体的指针参数来完成。 先定义一个结构体:

typedef struct
{
 int firstArgu,
 long secondArgu,
…
}myType,*pMyType;
创建线程时
CreateThread(NULL,0,threadFunc,pMyType,…);

在threadFunc函数内部,可以使用“强制转换”:

int intValue=((pMyType)lpvoid)->firstArgu;
long longValue=((pMyType)lpvoid)->seconddArgu;
……
例程3 MultiThread3将演示如何传送一个指向结构体的指针参数。

  1. 建立一个基于对话框的工程MultiThread3,在对话框IDD_MULTITHREAD3_DIALOG中加入一个编辑框IDC_MILLISECOND,一个按钮IDC_START,标题为“开始” ,一个进度条IDC_PROGRESS1;
  2. 打开ClassWizard,为编辑框IDC_MILLISECOND添加int型变量m_nMilliSecond,为进度条IDC_PROGRESS1添加CProgressCtrl型变量m_ctrlProgress;
  3. 在MultiThread3Dlg.h文件中添加一个结构的定义:
    struct threadInfo
    {
    	UINT nMilliSecond;
    	CProgressCtrl* pctrlProgress;
    };
    
    线程函数的声明:
    UINT ThreadFunc(LPVOID lpParam);
    
    注意,二者应在类CMultiThread3Dlg的外部。 

    在类CMultiThread3Dlg内部添加protected型变量:
    HANDLE hThread;
    DWORD ThreadID;
    
    分别代表线程的句柄和ID。
  4. 在MultiThread3Dlg.cpp文件中进行如下操作:

    定义公共变量 threadInfo Info;
    双击按钮IDC_START,添加相应消息处理函数:
    void CMultiThread3Dlg::OnStart() 
    {
    	// TODO: Add your control notification handler code here
    
    	UpdateData(TRUE);
    	Info.nMilliSecond=m_nMilliSecond;
    	Info.pctrlProgress=&m_ctrlProgress;
    
    	hThread=CreateThread(NULL,
    		0,
    		(LPTHREAD_START_ROUTINE)ThreadFunc,
    		&Info,
    		0,
    		&ThreadID);
    /*
    	GetDlgItem(IDC_START)->EnableWindow(FALSE);
    	WaitForSingleObject(hThread,INFINITE);
    	GetDlgItem(IDC_START)->EnableWindow(TRUE);
    */
    }
    
    在函数BOOL CMultiThread3Dlg::OnInitDialog()中添加语句:
    {
    	……
    	
    	// TODO: Add extra initialization here
    	m_ctrlProgress.SetRange(0,99);
    	m_nMilliSecond=10;
    	UpdateData(FALSE);
    	return TRUE;  // return TRUE  unless you set the focus to a control
    }
    
    添加线程处理函数:UINT ThreadFunc(LPVOID lpParam)
    {
    	threadInfo* pInfo=(threadInfo*)lpParam;
    	for(int i=0;i<100;i++)
    	{
    		int nTemp=pInfo->nMilliSecond;
    
    		pInfo->pctrlProgress->SetPos(i);
    
    		Sleep(nTemp);
    	}
    	return 0;
    }
    
      顺便补充一点,如果你在void CMultiThread3Dlg::OnStart() 函数中添加/* */语句,编译运行你就会发现进度条不进行刷新,主线程也停止了反应。什么原因呢? 这是因为WaitForSingleObject函数等待子线程(ThreadFunc)结束时,导致了线程死锁。因为WaitForSingleObject函数会将主线程挂起(任何消息都得不到处理),而子线程ThreadFunc正在设置进度条,一直在等待主线程将刷新消息处理完毕返回才会检测通知事件。这样两个线程都在互相等待,死锁发生了,编程时应注意避免。
例程4 MultiThread4

该例程测试在Windows下最多可创建线程的数目。

  1. 建立一个基于对话框的工程MultiThread4,在对话框IDD_MULTITHREAD4_DIALOG中加入一个按钮IDC_TEST和一个编辑框IDC_COUNT,按钮标题为“测试” , 编辑框属性选中Read-only;
  2. 在MultiThread4Dlg.cpp文件中进行如下操作:

    添加公共变量
    volatile BOOL m_bRunFlag=TRUE; 

    该变量表示是否还能继续创建线程。

    添加线程函数:

    DWORD WINAPI threadFunc(LPVOID threadNum)
    {
    	while(m_bRunFlag)
    	{
    		Sleep(3000);
    	}
    	return 0;
    }
    
    只要 m_bRunFlag 变量为TRUE,线程一直运行。

    双击按钮IDC_TEST,添加其响应消息函数:
    void CMultiThread4Dlg::OnTest() 
    {
    	DWORD threadID;
    	GetDlgItem(IDC_TEST)->EnableWindow(FALSE);
    	long nCount=0;
    	while(m_bRunFlag)
    	{
    		if(CreateThread(NULL,0,threadFunc,NULL,0,&threadID)==NULL)
    		{
    			m_bRunFlag=FALSE;
    			break;
    		}
    		else
    		{
    			nCount++;
    		}
    	}
       //不断创建线程,直到再不能创建为止
    	m_nCount=nCount;
    	UpdateData(FALSE);
    	Sleep(5000);
       //延时5秒,等待所有创建的线程结束
    	GetDlgItem(IDC_TEST)->EnableWindow(TRUE);
        m_bRunFlag=TRUE;
    }

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

MFC多线程编程之一——问题提出 的相关文章

  • 如何在 C 中使用 write() 函数写入整数? [复制]

    这个问题在这里已经有答案了 我是 C 菜鸟 正在尝试使用write 显示整数的函数 这是我的代码 int n 7 write 1 n 4 我想展示7 但是当我设置时程序没有显示任何内容或其他奇怪的字符n到一个大数字 我缺少什么 类似的对象i
  • 跨平台 Windows / OS X 开发,具有大量现有代码库

    对于使用 MFC 和 WinAPI 用 C 编写的复杂应用程序 有大量现有代码库 需要将其移植到 Mac OS X 理想的解决方案是在不同平台之间拥有尽可能多的通用代码 尤其是诸如业务之类的代码逻辑 GUI 可能会有所不同 具体取决于跨平台
  • 如何在haskell中反转整数?

    我需要有关如何逆转的帮助Integer在 Haskell 中具有以下类型签名 reverseInt Integer gt Integer reverseInt a undefined help here 我需要Integer输入要反转的数字
  • 创建非托管常规 MFC DLL 并从托管 C++ .NET 应用程序调用它时出现问题

    我有几个关于 DLL 的问题 我尝试了很多 但无法获得完整的图片 大多数示例都是用 C 等编写的 使用 VS2005 中的向导 我创建了一个非托管 MFC 常规 DLL 由于剩余代码 必须是 MFC 然后我尝试将其导入 VS2005 管理的
  • Ruby 中的安全整数解析

    我有一根绳子 比如说 123 我想将它转换为整数123 我知道你可以简单地做some string to i 但这会转换 lolipops to 0 这不是我想要的效果 当我试图用一种美好而痛苦的方式转换一些无效的东西时 我希望它在我脸上爆
  • Ruby 中的大乘法输出结果为负

    我写了一些代码 应该对 1 sum 0 1 1000 each do n sum n n puts n n sum sum end 由于某种原因 在数字 28 之后输出为负值 n 29 sum 20154009777005735238923
  • 编辑默认工具栏时 Microsoft Visual Studio“未知位图格式”

    我已使用项目创建向导使用 Microsoft 基础类库 MFC 创建了一个应用程序 我创建了一个多文档界面 MDI 应用程序 该向导创建您可以使用的虚拟工具栏和菜单 我扩展了默认工具栏 没有任何问题 但是现在当我尝试通过资源视图编辑它时 我
  • 如何发光最小。最大和关闭按钮?

    我按照以下指南使用 DWM API 创建自定义 Aero 框架 My work void CMainFrame OnActivate UINT nState CWnd pWndOther BOOL bMinimized CFrameWnd
  • 鲁比“是吗?”需要类或模块(类型错误)

    我正在使用 Ruby 并尝试创建一个小型银行帐户程序 当我运行在 create account 中运行的这一特定代码行时 unless response is a Integer response to str length 4 puts
  • 如果可能的话,如何在 C 中定义 2 位数字?

    对于我的大学过程 我正在模拟一个称为随机顺序吸附的过程 我必须做的一件事是随机地将正方形 不能重叠 放置到格子上 直到没有更多空间为止 重复该过程几次以找到平均 干扰 覆盖率 基本上我正在对一个大的整数数组执行操作 其中存在 3 个可能的值
  • Javascript解析int64

    如何将长整数 作为字符串 转换为 Javascript 中的数字格式而不用 javascript 对其进行四舍五入 var ThisInt 9223372036854775808 alert ThisInt r parseFloat Thi
  • 在Linux上运行MFC程序

    我有一个相当大的基于 MFC 的程序 我的任务是让它在 Linux 上运行 我已经解释过 这需要将程序重新编写为带有 STL 的直接 C 更多工作 或者重新编写为 Qt C 更少工作 现在我被告知 我需要编写包装器以使每个 MFC 类在 L
  • 如何在VC++/MFC中替换字符串中两个子字符串之间的字符串?

    假设我有一个 CString 对象 strMain AAAABBCCCCCCDDBBCCCCCCCCDDDAA 我还有两个较小的字符串 例如 strSmall1 BB strSmall2 DD 现在 我想替换 strMain 中 strSm
  • mysql中auto_increment(整数)的限制是多少

    我有一个mysql数据库 我在其中使用auto increment integer 你能告诉我它可以增加多少整数吗 我们如何提高auto increment的限制 的极限auto increment column 是列的大小 https d
  • 如何在Python中将列表中的整数相加(对数字列表求和)?

    假设我有一个整数列表 例如 2 4 7 12 3 我怎样才能将所有数字加在一起 以获得28 x 2 4 7 12 3 sum of all numbers sum x 或者你可以尝试这个 x 2 4 7 12 3 sum of all nu
  • 如何使Python中的浮点值显示.00而不是.0?

    简单的问题 抱歉我无法弄清楚 我有一些数字是由 浮动 字符串 它们显示为 xxx 0 但如果确实是整数 我希望它们以 00 结尾 我该怎么做 Thanks EDIT Python 说 float 没有 cal format gt gt gt
  • Lua中如何获取表中的最大整数?

    Lua中如何获取表中的最大整数 在Lua 5 1及更早版本中 你可以使用 math max unpack 1 2 3 4 5 这受到Lua堆栈大小的限制 在 PUC Lua 5 1 上 该值的最大值可达 ca 8000 个数字 如果堆栈空闲
  • 整数构造变体

    大家好 我遇到了一个有趣的事件 正在寻找解释 在 Java 1 6 中 Integer a new Integer 5 Integer b new Integer 5 System out println a b Integer c 5 I
  • 如何通过MFC将应用程序设置保存到注册表中?

    我有一个由 MFC 项目向导创建的 MFC 应用程序 我想在注册表中保存 读取应用程序设置 所以问了这个question https stackoverflow com questions 1880275 good c registry w
  • 分组为连续整数范围

    我检查了其他帖子 包括使用 Linq 按可变整数范围进行分组 https stackoverflow com questions 1375997 group by variable integer range using linq 但我没有

随机推荐

  • 【Golang入门】Golang第一天心得

    生活所迫 入门一下Go 很奇葩的第一点 接口 package main import fmt 定义一个接口 type Shape interface Area float64 定义一个矩形类型 type Rectangle struct W
  • 企业级体验:未来体验管理的价值与趋势

    我从事企业级体验相关领域的工作已十六载有余 曾经就职的企业既有阿里巴巴 腾讯这样的互联网 大厂 也有顺丰 龙湖这样的线下 传统 企业 在这些企业中 我所工作的场景横跨了软件 电商 互联网 物流 零售 地产 金融等诸多业务领域 为不同业务场景
  • freeImage图像旋转滤波

    原文 http www cnblogs com wangshide archive 2012 04 25 2470693 html 1 使用了 freeImage 图像库进行图像读取 保存 如何将图片转为矩阵 如何处理图片的颜色 rgb 透
  • pandas笔记(10)——数据导出

    导出excel 格式 to excel excel writer sheet name Sheet1 na rep float format None columns None header True index True index la
  • springcloud-eureka集群-整合hystrix框架整合feign

    继之前的项目继续扩展 整合hystrix和feign这两个框架 1 修改服务器调用者的application yml 增加如下代码 打开feign对hystrix的支持 feign hystrix enabled true 配置hystri
  • STM3利用FATFS向SD卡文件追加数据的三种方法

    1 f sync SDFile 该方法简单粗暴 适合一直连续向sd卡中写入数据 while之前就f open 循坏内重复 向缓存填充数据 gt 写入数据 gt 刷新写入 整个过程并没有f colse retSD f open SDFile
  • Win10 LTSB/LTSC 录音机、图片查看器、便签

    Win10 LTSB LTSC 录音机 图片查看器 便签 文章目录 Win10 LTSB LTSC 录音机 图片查看器 便签 示例 录音机 图片查看器 便签 示例 文件下载地址 链接 https pan baidu com s 1YYwh9
  • etree.html 报错 AttributeError:‘function’ object has no attribut ‘HTML’

    etree html 报错 1 Pycharm 中lxml没有etree模块的解决方法 之前是 from lxml import etree tree etree HTML python 3 5以上版本lxml中没有了etree 要换另外一
  • Windows 环境下安装C语言运行环境

    STEP1 下载min gw 下载地址 https sourceforge net projects mingw files STEP2 点击 mingw get setup exe安装 安装目录可以自己选择 但是要记住 后面添加环境变量需
  • 离散数学---期末复习知识点

    一 数理逻辑 复习知识点 1 命题与联结词 否定 析取 合取 蕴涵 等价 命题 非真既假的陈述句 复合命题 由简单命题通过联结词联结而成的命题 2 命题公式与赋值 成真 成假 真值表 公式类型 重言 矛盾 可满足 公式的基本等值式 3 范式
  • 机器学习编程作业-逻辑回归

    逻辑回归 作业说明 复习 任务一 使用逻辑回归辨别真假钞票 任务二 使用逻辑回归对电影评论分类 作业说明 任务一 使用逻辑回归辨别真假钞票 钞票数据集 Banknote Dataset 涉及根据给定钞票的数个度量的照片预测是真钞还是假钞 它
  • vue-element-admin项目

    vue element admin vue element admin 介绍 功能 前序准备 目录结构 项目运行机制和代码注释 main js App vue permission js Vuex结构 scss icons 安装 Contr
  • 密码学之DES算法简述(1)

    1 DES算法描述 1 输入64位明文数据 并进行初始置换IP 2 在初始置换IP后 明文数据再被分为左右两部分 每部分32位 以L0 R0表示 3 在秘钥的控制下 经过16轮运算 f 4 16轮后 左 右两部分交换 并连接再一起 再进行逆
  • MyBatis中将结果集封装到指定类型详解(反射Class.forName详解)

    文章目录 1 将结果集封装到指定类型中 1 1指定类型 1 2将信息存入到mapper中 1 3反射 1 3 1获取全限定类名 加载类并且实例化 1 3 2执行SQL语句 生成的结果集获取元信息 把每列的数据存入到指定类型中 1 4Clas
  • java正则表达式语法详解及其使用代码实例

    代码下载地址 http www zuidaima com share 1835085544524800 htm 原文 java正则表达式语法详解及其使用代码实例 Regular Expressions of Java Tutorial 译者
  • Community宣言

    Community宣言 一个幽灵 共产主义的幽灵 在欧洲游荡 为了对这个幽灵进行神圣的围剿 旧欧洲的一切势力 教皇和沙皇 梅特涅和基佐 法国的激进派和德国的警察 都联合起来了 有哪一个反对党不被它的当政的敌人骂为Community呢 又有哪
  • 【python知识点】锦集

    版权声明 未经博主同意 谢绝转载 请尊重原创 博主保留追究权 https blog csdn net m0 69908381 article details 132368704 出自 进步 于辰的博客 相关博文 python细节 经验 锦集
  • 老电脑如何用U盘重装系统?老电脑用U盘重装系统教程

    老电脑如何用U盘重装系统 用户利用U盘来给老电脑重装系统 能够帮助解决老电脑运行缓慢 系统出现故障或感染病毒等问题 通过重装系统 可以清除旧的系统文件和应用程序 重新安装一个干净且高效的操作系统 那么具体要如何操作 可以参考以下小编分享的老
  • 微信小程序开发(八)button按钮去除圆角

    背景 小程序使用button 会有一个默认圆角 如果修改数值比较容易 想要去掉就可能遇到坑 原因 小程序的设计风格是button的border和圆角等都是通过after写的 如果需要去掉圆角效果 最好是使用如下代码 button borde
  • MFC多线程编程之一——问题提出

    原文地址 http www vckbase com document viewdoc id 1704 一 问题的提出 编写一个耗时的单线程程序 新建一个基于对话框的应用程序SingleThread 在主对话框IDD SINGLETHREAD