#7 C++高级--内存管理、文件处理、多线程
目录
- 1. 内存管理
- 1.1. 基础
- 1.1.1. 程序的内存分配
- 1.2. 释放 与 销毁
- 1.2.1. 部分
- 1.2.2. MFC
- 1.2.3. 非模态窗口 关闭
- 1.1. 基础
- 2. 文件处理 // 文件
- 2.1. 文件和流
- 2.1.1. 创建 删除 文件 文件夹
- 2.1.2. 创建文件夹
- 2.1.3. 删除文件夹
- 2.1.4. 判断是否存在 文件、文件夹
- 2.1.5. 打开与关闭
- 2.1.6. 读取和写入
- 2.1.7. 文件位置指针
- 2.2. 帮助文档
- 2.1. 文件和流
- 3. 多线程
- 3.1. 多线程 概述
- 3.1.1. 堆和栈
- 3.1.2. 进程和线程有什么区别?
- 3.1.3. 线程同步与互斥
- 3.2. 线程的基本操作
- 3.2.1. 基本函数
- 3.2.2. 线程的创建
- 3.2.3. 线程的挂起、唤醒和终止
- 3.3. 线程同步
- 3.3.1. 关键段CS CRITICAL_SECTION
- 3.3.2. 事件 Event
- 3.3.3. 互斥量 Mutex
- 3.3.4. 信号量 Semaphore
- 3.4. 线程间通信
- 3.1. 多线程 概述
第7章 C++ 高级
1. 内存管理
1.1. 基础
参考:
- C++多线程编程之常见面试问题
1.1.1. 程序的内存分配
一个由**C/C++**编译的 程序占用的内存分为以下几个部分:
- 栈区(stack)— 由编译器自动分配释放
,存放函数的参数名,局部变量的名等。其操作方式类似于数据结构中的栈。 - 堆区(heap)— 由程序员分配释放,
若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。 - 全局区(静态区)(static)—全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,
未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。 - 文字常量区—常量字符串就是放在这里的,程序结束后由系统释放 。
- 程序代码区— 存放函数体的二进制代码。
1.2. 释放 与 销毁
1.2.1. 部分
1.2.2. MFC
参考:
- MFC创建非模态对话框和销毁过程 //命令和消息的传递
1.2.3. 非模态窗口 关闭
- MFC应用程序关闭窗口的顺序(非模态窗口)
- OnClose()
消息响应函数,响应窗口的WM_CLOSE消息,当关闭按钮被单击的时候发送此消息 - OnDestroy()
消息响应函数,响应窗口的WM_DESTROY消息,当一个窗口将被销毁时,发送此消息 - OnNcDestroy()
消息响应函数,响应窗口的WM_NCDESTROY消息,当一个窗口被销毁后发送此消息 - PostNcDestroy() 重载函数,作为处理OnNcDestroy()函数的最后动作,被CWnd调用。
- OnClose()
2. 文件处理 // 文件
2.1. 文件和流
- 从文件读取流和向文件写入流需要用到 C++ 中另一个标准库fstream,
- 它定义了三个新的数据类型:
- ofstream:表示输出文件流,用于创建文件并向文件写入信息。
- ifstream:表示输入文件流,用于从文件读取信息。
- fstream:通常表示文件流,且同时具有 ofstream 和 ifstream
两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。
//注:- i fstream 即i(n) f //输入到程序 读取 //程序是主体
- o fstream 即o(ut) f //输出到程序 写入
注:
- 在 C++ 中进行文件处理,必须在 C++ 源代码文件中包含头文件
<iostream>
和<fstream>
。
2.1.1. 创建 删除 文件 文件夹
//“创建文件夹” “删除文件夹”
2.1.2. 创建文件夹
使用 WINAPI 函数
调用Windows API函数 *CreateDirectory()*和 *RemoveDirectory()* *成功返回0,否则返回非零* bool flag = CreateDirectory(path.c_str(), NULL); *判断文件夹是否存在 再创建* # include <windows.h> # include <iostream> using namespace *std*; int main() { *string* defaultPath = "E:database"; *string* folderPath = defaultPath + "testFolder"; if (!*GetFileAttributesA*(folderPath.*c_str*()) & *FILE_ATTRIBUTE_DIRECTORY*) { bool flag = *CreateDirectory*(folderPath.*c_str*(), *NULL*); // flag 为 true 说明创建成功 } else { *cout* << "Directory already exists." << *endl*; } return 0; }
使用 dos 命令
参考:
- C++ 创建文件夹的四种方式
- C/C++创建和删除文件夹操作(对单个文件夹进行操作)
2.1.3. 删除文件夹
- WINAPI函数
成功返回0,否则返回非零
bool flag = RemoveDirectory(path.c_str());
2.1.4. 判断是否存在 文件、文件夹
//“创建文件夹”、“创建文件”、“文件是否重复”、‘文件重复’
GetFileAttributesA( ) 函数 //文件夹
DWORD d = GetFileAttributesA(const char* filename); #include <windows.h> // windows系统函数, 判断**文件夹**是否存在; // 见 *参考2*
_access( ) 函数 //文件
//参考 2Visual Studio 2015 //文件
//文件是否存在
使用 .open 函数来打开文件,看是否存在
// 但存在则已经打开,需要关闭 不推荐使用
参考:
- 在C++中检查一个文件是否存在的几种方法
- C++ 判断文件夹(folder)是否存在(exist) //推荐
- C++中如何判断文件是否存在 //.open 不推荐
2.1.5. 打开与关闭
打开文件
在从文件读取信息或者向文件写入信息之前,必须先打开文件。ofstream 和 fstream
对象都可以用来打开文件进行写操作,如果只需要打开文件进行读操作,则使用 ifstream
对象。语句格式
void open(const char *filename, ios::openmode mode); //open() 成员函数的第一参数指定要打开的文件的名称和位置 //第二个参数定义文件被打开的模式 //open() 函数是 fstream、ifstream 和 ofstream 对象的一个成员。
代码示例:
ofstream outfile; outfile.open("file.dat", ios::out | ios::trunc); //将两种方式结合使用
关闭文件
当 C++程序终止时,它会自动关闭刷新所有流,释放所有分配的内存,并关闭所有打开的文件。但程序员应该养成一个好习惯,在程序终止前关闭所有打开的文件。语句格式
void close(); //close() 函数是 fstream、ifstream 和 ofstream 对象的一个成员
2.1.6. 读取和写入
在 C++编程中,我们使用流提取运算符(>>)从文件读取信息,就像使用该运算符从键盘输入信息一样。唯一不同的是,在这里您使用的是ifstream或fstream对象,而不是cin对象。
//cin是对象,而不是函数
- 读取&写入 代码示例:
#include <fstream> #include <iostream> //引入头文件 using namespace std; int main() { char data[100]; // 以写模式打开文件 ofstream outfile; outfile.open("afile.dat"); cout << "Writing to the file" << endl; cout << "Enter your name: "; cin.getline(data, 100); // 向文件写入用户输入的数据 outfile << data << endl; cout << "Enter your age: "; cin >> data; cin.ignore(); // 再次向文件写入用户输入的数据 outfile << data << endl; // 关闭打开的文件 outfile.close(); // 以读模式打开文件 ifstream infile; infile.open("afile.dat"); cout << "Reading from the file" << endl; infile >> data; // 在屏幕上写入数据 cout << data << endl; // 再次从文件读取数据,并显示它 infile >> data; cout << data << endl; // 关闭打开的文件 infile.close(); return 0; }
2.1.7. 文件位置指针
2.2. 帮助文档
- CHM 帮助文件
3. 多线程
参考:
- 为什么要多线程开发
- 多线程笔试面试题汇总
//主要
3.1. 多线程 概述
做到:主线程与子线程之间的同步;各子线程间的互斥。
参考:
- 秒杀多线程系列
多线程笔试面试题汇总 共16篇 //主要 讲解详细 - C++ 多线程 面试题详解 //很少
- C++多线程编程之常见面试问题
- C++ 11 多线程–线程管理
- 程序员的自我修养(五):C++多线程编程初步
3.1.1. 堆和栈
堆:
是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。栈:
是个线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立,因此,栈是 thread
safe的。每个C ++对象的数据成员也存在在栈中,每个函数都有自己的栈,栈被用来在函数之间传递参数。操作系统在切换线程的时候会自动的切换栈,就是切换SS/ESP寄存器。栈空间不需要在高级语言里面显式的分配和释放。
3.1.2. 进程和线程有什么区别?
这个一个最常见,却最不好回答的问题,csdn上面一位博主给出的解答和另一位cnblog博主的解答稍微清晰些一些,
总结起来,就是一下的几个区别:
- 进程是资源分配的基本单位,线程是cpu调度,或者说是程序执行的最小单位。在Mac、Windows
NT等采用微内核结构的操作系统中,进程的功能发生了变化:它只是资源分配的单位,而不再是调度运行的单位。在微内核系统中,真正调度运行的基本单位是线程。因此,实现并发功能的单位是线程。 - 进程有独立的地址空间,比如在linux下面启动一个新的进程,系统必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种非常昂贵的多任务工作方式。而运行一个进程中的线程,它们之间共享大部分数据,使用相同的地址空间,因此启动一个线程,切换一个线程远比进程操作要快,花费也要小得多。当然,线程是拥有自己的局部变量和堆栈(注意不是堆)的,比如在windows中用_beginthreadex创建一个新进程就会在调用CreateThread的同时申请一个专属于线程的数据块(_tiddata)。
- 线程之间的通信比较方便。统一进程下的线程共享数据(比如全局变量,静态变量),通过这些数据来通信不仅快捷而且方便,当然如何处理好这些访问的同步与互斥正是编写多线程程序的难点。而进程之间的通信只能通过进程通信的方式进行。
- 多进程比多线程程序要健壮。一个线程死掉整个进程就死掉了,但是在保护模式下,一个进程死掉对另一个进程没有直接影响。
- 线程的执行与进程是有区别的。每个独立的线程有有自己的一个程序入口,顺序执行序列和程序的出口,但是线程不能独立执行,必须依附与程序之中,由应用程序提供多个线程的并发控制。
- 进程是资源分配的基本单位,线程是cpu调度,或者说是程序执行的最小单位。在Mac、Windows
3.1.3. 线程同步与互斥
参考:
- https://blog.csdn.net/morewindows/article/details/7538247
- 详解
线程(进程)同步的主要任务:
在引入多线程后,由于线程执行的异步性,会给系统造成混乱,特别是在急用临界资源时,如多个线程急用同一台打印机,会使打印结果交织在一起,难于区分。当多个线程急用共享变量,表格,链表时,可能会导致数据处理出错,因此线程同步的主要任务是使并发执行的各线程之间能够有效的共享资源和相互合作,从而使程序的执行具有可再现性。线程(进程)之间的制约关系?
间接相互制约可以称为互斥,直接相互制约可以称为同步,对于互斥可以这样理解,线程A和线程B互斥访问某个资源则它们之间就会产个顺序问题——要么线程A等待线程B操作完毕,要么线程B等待线程A操作完毕,这其实就是线程的同步了。
因此同步包括互斥,互斥其实是一种特殊的同步。临界资源和临界区
在一段时间内只允许一个线程访问的资源就称为临界资源或独占资源,计算机中大多数物理设备,进程中的共享变量等待都是临界资源,
它们要求被互斥的访问。每个进程中访问临界资源的代码称为临界区。
3.2. 线程的基本操作
3.2.1. 基本函数
- WaitForSingleObject 与 WaitForMultipleObjects
To enter an alertable wait state, use the WaitForSingleObjectEx function.
To wait for multiple objects, useWaitForMultipleObjects. - WaitForSingleObject
Waits until the specified object is in the signaled state or the time-out
interval elapses. - WaitForMultipleObjects
参考:
- WaitForSingleObject与WaitForMultipleObjects用法详解
3.2.2. 线程的创建
//4种创建方法;
3.2.3. 线程的挂起、唤醒和终止
3.3. 线程同步
参考:
- 秒杀多线程系列
多线程笔试面试题汇总 //主要 讲解详细 - VC++ 从入门到精通
概述
定义:
线程同步:- 即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作,
- 而其他线程又处于等待状态,实现线程同步的方法有很多,临界区对象就是其中一种。
//百度百科
// 单线程的 对 内存 的有序操作;
目的:
解决线程对于 资源访问冲突 的问题,例如,同时访问;访问后更改,不同步的问题;
方法:
- 关键段CS //秒杀多线程第五篇 经典线程同步
CRITICAL_SECTION - 事件Event //秒杀多线程第六篇 经典线程同步
- 互斥量Mutex //秒杀多线程第七篇 经典线程同步
- 信号量Semaphore //秒杀多线程第八篇 经典线程同步
- 关键段CS //秒杀多线程第五篇 经典线程同步
线程同步方式比较:
- 用户模式下的方法有:原子操作(例如一个单一的全局变量),临界区。
- 内核模式下的方法有:事件,信号量,互斥量。
- 概述:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O4YJ5uiK-1591631942702)(media/43f353835e351274b95e391e8e8401a3.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kjcxjEOv-1591631942705)(media/b92928decd7be281afe8645f4998369b.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dQMytPrK-1591631942707)(media/8eef1efa5ba4282823b1b836659b3096.png)]
3.3.1. 关键段CS CRITICAL_SECTION
总结:
- 关键段共初始化化、销毁、进入和离开关键区域四个函数。
- 关键段可以解决线程的互斥问题,但因为具有“线程所有权”,所以无法解决同步问题。
- 推荐关键段与旋转锁配合使用。
关键段CRITICAL_SECTION一共就四个函数,使用很是方便。
- 初始化:
void InitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
函数说明:定义关键段变量后必须先初始化。 - 销毁:
void DeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
函数说明:用完之后记得销毁。 - 进入关键区域:
void EnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
函数说明:系统保证各线程互斥的进入关键区域。 - 离开关键区域:
void LeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
- 初始化:
3.3.2. 事件 Event
总结:
- 事件是内核对象,事件分为手动置位事件和自动置位事件。事件Event内部它包含一个使用计数(所有内核对象都有),一个布尔值表示是手动置位事件还是自动置位事件,另一个布尔值用来表示事件有无触发。
- 事件可以由SetEvent()来触发,由ResetEvent()来设成未触发。还可以由PulseEvent()来发出一个事件脉冲。
- 事件可以解决线程间同步问题,因此也能解决互斥问题。
事件对象属于系统内核对象之一;分为手动置位事件和自动置位事件;
- 手动置位事件
等待到事件对象后,可同时使多个线程成为可调度线程; - 自动置位事件
等待到事件对象后,多个线程中只有一个成为可调度线程;并将事件对象设置为未通知状态;
//2个动作
- 函数:
HANDLE CreateEvent() 创建事件; HANDLE OpenEvent() 根据名称获得一个事件的句柄; BOOLSetEvent(HANDLEhEvent); BOOLResetEvent(HANDLEhEvent); CloseHandle(); 清理和销毁;
- 手动置位事件
3.3.3. 互斥量 Mutex
总结:
- 互斥量是内核对象,它与关键段都有“线程所有权”;所以不能用于线程的同步。
- 互斥量能够用于多个进程之间线程互斥问题,并且能完美的解决某进程意外终止所造成的**“遗弃”**问题。
函数:
HANDLE CreateMutex(); HANDLE OpenMutex(); BOOL ReleaseMutex (HANDLEhMutex);
3.3.4. 信号量 Semaphore
- 总结:
- 信号量也可以解决线程之间的同步问题。
- 由于信号量可以计算资源当前剩余量并根据当前剩余量与零比较来决定信号量是处于触发状态或是未触发状态,因此信号量的应用范围相当广泛。
- 函数:
HANDLE CreateSemaphore(); HANDLE OpenSemaphore(); BOOL ReleaseSemaphore(); CloseHandle(); //清理和销毁;通用;
3.4. 线程间通信
参考:
- 线程之间的通信
- 线程之间的通信(thread signal)
#7 C++高级--内存管理、文件处理、多线程相关推荐
- [iOS]Advanced Memory Management Programming Guide 高级内存管理编程指南(官方文档翻译)
Advanced Memory Management Programming Guide - 高级内存管理编程指南(官方文档翻译) 版权声明:本文为博主原创翻译,如需转载请注明出处. 新博客文章地址: ...
- JS高级——内存管理和闭包
0.预备知识 0.1 认识内存管理 不管什么样的编程语言,在代码的执行过程中都是需要给它分配内存的,不同的是某些编程语言需要我们自己手动的管理内存,某些编程语言会可以自动帮助我们管理内存: 不管以什么 ...
- MySQL高级-内存管理及优化
1 内存优化原则 1) 将尽量多的内存分配给MySQL做缓存,但要给操作系统和其他程序预留足够内存. 2) MyISAM 存储引擎的数据文件读取依赖于操作系统自身的IO缓存,因此,如果有MyISAM表 ...
- 【Contact】结构体+动态内存管理+文件存储实现简易通讯录代码
目录 静态版本 test.c contact.h contact.c 动态版本 test.c contact.h contact.c 文件的版本 test.c contact.h contact.c ...
- 《Objective-C高级编程 iOS与OS X多线程和内存管理》读书笔记
<Objective-C高级编程 iOS与OS X多线程和内存管理>读书笔记 第一章:自动引用计数 自己生成的对象,自己所持有. 非自己生成的对象,自己也能持有 不再需要自己持有的对象时释 ...
- 【Java书笔记】:《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》第2部分-自动内存管理,第3部分-虚拟机执行子系统,第5部分-高效并发
作者:周志明 整理者GitHub:https://github.com/starjuly/UnderstandingTheJVM 第2部分-自动内存管理 第2章 Java内存区域与内存溢出异常 2.2 ...
- cocos2dx多线程以及线程同步 与 cocos2dx内存管理与多线程问题
cocos2d-x引擎在内部实现了一个庞大的主循环,每帧之间更新界面,如果耗时的操作放到了主线程中,游戏的界面就会卡,这是不能容忍的,游戏最基本的条件就是流畅性,这就是为什么游戏开发选择C++的原因. ...
- LevelDB 源码剖析(三)公共基础:内存管理、数值编码、Env家族、文件操作
文章目录 内存管理 Arena 结构 内存分配 内存使用率统计 TCMalloc Env家族 PosixEnv EnvWrapper InMemoryEnv 文件操作 SequentialFile W ...
- 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
本文背景: 在编程中,很多Windows或C++的内存函数不知道有什么区别,更别谈有效使用:根本的原因是,没有清楚的理解操作系统的内存管理机制,本文企图通过简单的总结描述,结合实例来阐明这个机制. 本 ...
最新文章
- PHP 批量生成静态html
- 内存溢出和内存泄漏的区别、产生原因以及解决方案
- MyBatis入门2
- Linux dmesg 命令学习
- 设计模式之观察者模式--中英文结合理解版
- jQuery 一些操作
- 我对计算机感兴趣作文300字,我想对电脑游戏说作文300字
- defender 报备_去体育中心游泳碰上竞训怎么办?酒店承接会议业务需要报备吗?部门这样说...
- SourcesTree使用手册2:文件更新
- CSDN西安分站俱乐部聚会归来记
- Atitit 安全流程法 目录 1. 常见等安全措施方法	2 1.1. 安全的语言 代码法,编译型 java	2 1.2. 安全编码法	2 1.3. 安全等框架类库 api	2 1.4. 加密法	2
- python enumerate() 函数的使用方法
- thinkphp3.2.3 d方法调用自定义模型_啥?Android 11 不能自定义 Toast 了?
- 推荐收藏:50个最佳机器学习公共数据集
- 信息学奥赛一本通1045
- 一元线性回归:Excel、SPSS、Matlab三种方法实现
- pscc2018教程photoshop软件全套入门到精通分享
- Mac便捷小工具收集
- 2020年,你必须掌握的前端技术栈
- 使用wxPython开发带有GUI图形界面的Python程序简单实例
热门文章
- ​2019胡润百富榜公布:中国互联网上演: 龙虎斗 , 阿里暂时领跑 , 企鹅紧随其后 , 李彦宏,雷军掉队...
- 文件管理android2.3,华为手机文件管理器(com.huawei.hidisk) - 10.11.11.301 - 应用 - 酷安...
- Druid middleManager如何获取task信息并启动Peon进程
- 基于ug的框架断路器抽屉座运动仿真
- 【陈秀秀往事】---一个战痘8年成功的感人故事!
- 北大数学系「扫地僧」韦东奕爆红!拒绝哈佛offer,留任北大,却因长相引热议...
- 计算机上配置静态ip,如何给电脑设置固定IP地址
- 刚开始做软件测试,一般工资范围是多少?
- 【实战】如何抓住Facebook天秤币的机会
- 论文笔记:AAAI 2021 Beyond Low-frequency Information in Graph Convolutional Networks