iOS笔记058 - IOS之多线程
IOS开发中多线程
- 主线程
- 一个iOS程序运行后,默认会开启1条线程,称为“主线程”或“UI线程”
- 作用
- 显示和刷新界面
- 处理UI事件(点击、滚动、拖拽等)
- 注意事项
- 耗时操作不能放在主线程中没,比如资源记载,文件下载,等比较耗时间的任务,不然会卡死界面
- 可以将耗时操作放到子线程中,将操作结果返回给主线程
- IOS中得几种多线程实现方案
pThread
- 一套通用的多线程API
- 适用于Unix\Linux\Windows等系统
- 跨平台\可移植
- 使用难度大
- C语言,手动管理线程生命周期
NSThread
- 使用更加面向对象
简单易用,可直接操作线程对象 - OC,手动管理线程生命周期
- 使用更加面向对象
GCD
- 旨在替代NSThread等线程技术,充分利用设备的多核
- C,自动管理
NSOperation
- 基于GCD(底层是GCD)
- 比GCD多了一些更简单实用的功能
- 使用更加面向对象
- OC,自动管理
其中GCD和NSOperation比较常用
pThread 的使用
// 多线程 pThread
pthread_t thread;
// 开启线程
pthread_create(&thread, NULL, run, NULL);
// 多线程 pThread
pthread_t thread1;
// 开启线程
pthread_create(&thread1, NULL, run, NULL);
void* run(void *para)
{
for (int i = 0 ;i < 10000; i ++) {
NSLog(@"run-%d----%@",i,[NSThread currentThread]);
}
return NULL;
}
NSThread 使用
- 这种方式创建的线程,在执行完线程函数里的方法后就由系统销毁了
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
// NSThread
// 创建NSThread
NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(threadRun:) object:@"鸟"];
NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(threadRun:) object:@"蛋"];
NSThread *thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(threadRun:) object:@"碎了"];
thread1.name = @"张三";
thread2.name = @"李四";
thread3.name = @"鸟";
// 开启线程
[thread1 start];
[thread2 start];
[thread3 start];
// 这种方法创建的线程无法获得线程对象,由系统管理
[NSThread detachNewThreadSelector:@selector(thread1:) toTarget:self withObject:@"狗蛋"];
}
- (void)threadRun:(id)obj
{
for (int i = 0 ;i < 100; i ++) {
NSLog(@"run-%d-%@---%@",i,obj,[NSThread currentThread]);
}
}
创建子线程的其他方法
- performSelectorInBackground
- performSelector
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
// 创建后台线程
[self performSelectorInBackground:@selector(thread1:) withObject:@"控制器"];
// 创建任务并添加到目标线程,可以是任意线程,子线程或者主线程
[self performSelector:@selector(thread2:) onThread:[NSThread mainThread] withObject:@"Main" waitUntilDone:NO];
}
- (void)thread1:(NSString *)str
{
for (int i = 0 ;i < 100; i ++) {
NSLog(@"run-%@---%@",str,[NSThread currentThread]);
}
}
- (void)thread2:(NSString *)str
{
for (int i = 0 ;i < 100; i ++) {
NSLog(@"run-%@---%@",str,[NSThread currentThread]);
}
}
线程的睡眠(阻塞)和退出
- (void)thread1:(NSString *)str
{
for (int i = 0 ;i < 100; i ++) {
NSLog(@"run-%d-%@---%@",i,str,[NSThread currentThread]);
if (i == 19) {
sleep(2); // 当前线程睡眠2s
}
else if( i == 33 )
{
[NSThread sleepForTimeInterval:2]; // 睡眠2s
}
else if(i == 40)
{
// 获取当前时间延后2s后的时间
NSDate *endDate = [NSDate dateWithTimeIntervalSinceNow:2];
[NSThread sleepUntilDate:endDate]; // 根据日期睡眠线程
}
else if(i == 55)
{
NSLog(@"结束线程");
[NSThread exit]; // 结束线程
}
}
}
线程同步 - 互斥锁
- 开启三个线程对同一个数据进行读写,就会出现问题,必须对读写数据进行处理,例如加锁
- 指令@synchronized()通过对一段代码的使用进行加锁。其他试图执行该段代码的线程都会被阻塞,直到加锁线程退出执行该段被保护的代码段,也就是说@synchronized()代码块中的最后一条语句已经被执行完毕的时候。
- @synchronized() 参数传入一个OC对象即可,self也可以
// 方法中对资源数的访问要加锁
- (void)saleTickets:(NSString *)str
{
// 三个消费者线程
while(1)
{
// 设置互斥锁
@synchronized (self)
{
// 获取资源数
NSInteger count = self.resourceCount;
if (count > 0) {
// 资源数减1
count -- ;
// 写入标记数据
self.resourceCount = count;
NSLog(@"%@消费了一个单位,还剩下%zd",[NSThread currentThread].name,count);
}
else
{
NSLog(@"资源全部使用完了");
break;
}
}
}
}
GCD
GCD - Grand Central Dispatch
GCD中任务和队列
- 任务:执行什么操作
- 队列:存放任务
使用方式
- 定制自己的任务,添加到队列即可。线程会有GCD自动创建和销毁。
并发队列+异步任务:创建多个线程,并发执行
/*
* 并发队列+异步任务:创建多个线程,并发执行
*/
- (void)concurrentAndAsync
{
// 创建一个并发队列
// 参数1:标识,一般用公司域名abc.com
// 参数2:队列类型:串行和并行两种
dispatch_queue_t queue = dispatch_queue_create("song.com", DISPATCH_QUEUE_CONCURRENT);
// 异步方式创建一个任务,任务不会立即执行
dispatch_async(queue, ^{
NSLog(@"1--%@--",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2--%@--",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3--%@--",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"4--%@--",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"5--%@--",[NSThread currentThread]);
});
// 先将以上任务全部添加完毕,然后这个函数结束,再开始并发执行线程
NSLog(@"dispatch_async--end -- %@--",[NSThread currentThread]);
// 执行结果
// dispatch_async--end -- <NSThread: 0x7ff3b1400b80>{number = 1, name = main}--
// 2--<NSThread: 0x7ff3b140bc40>{number = 2, name = (null)}--
// 1--<NSThread: 0x7ff3b16672e0>{number = 5, name = (null)}--
// 3--<NSThread: 0x7ff3b1556b20>{number = 3, name = (null)}--
// 4--<NSThread: 0x7ff3b165c760>{number = 4, name = (null)}--
// 5--<NSThread: 0x7ff3b1413aa0>{number = 6, name = (null)}--
}
- 并发队列+同步任务:不会开启新线程,在主线程中同步执行各个子线程,也就是逐一执行,并且是添加过任务后立即执行,之后才能添加下一个任务
/*
* 并发队列+同步任务:不会开启新线程,在父线程中同步执行各个子线程,也就是逐一执行,并且是添加过任务后立即执行,之后才能添加下一个任务
*/
- (void)concurrentAndSync
{
// 创建一个并发队列
// 参数1:标识,一般用公司域名abc.com
// 参数2:队列类型:串行和并行两种
dispatch_queue_t queue = dispatch_queue_create("song.com", DISPATCH_QUEUE_CONCURRENT);
// 同步方式创建任务,任务会立即执行,执行完成后才会继续向下执行
dispatch_sync(queue, ^{
NSLog(@"1--%@--",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2--%@--",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3--%@--",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"4--%@--",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"5--%@--",[NSThread currentThread]);
});
// 先将以上任务逐个依次执行完毕后才会执行这句话,并且多有任务的执行都在主线程里完成
NSLog(@"dispatch_sync--end -- %@--",[NSThread currentThread]);
// 输出结果如下
// 1--<NSThread: 0x7f9900711c90>{number = 1, name = main}--
// 2--<NSThread: 0x7f9900711c90>{number = 1, name = main}--
// 3--<NSThread: 0x7f9900711c90>{number = 1, name = main}--
// ......
// dispatch_sync--end -- <NSThread: 0x7f9900711c90>{number = 1, name = main}--
}
- 串行队列+同步任务:不会开启新线程,在父线程中同步执行各个子线程,也就是逐一执行,并且是添加过任务后立即执行,之后才能添加下一个任务
/*
* 串行队列+同步任务:不会开启新线程,在父线程中同步执行各个子线程,也就是逐一执行,并且是添加过任务后立即执行,之后才能添加下一个任务
*/
- (void)serialAndSync
{
// 创建一个串行队列
// 参数1:标识,一般用公司域名abc.com
// 参数2:队列类型:串行和并行两种
dispatch_queue_t queue = dispatch_queue_create("song.com", DISPATCH_QUEUE_SERIAL);
// 同步方式创建任务,任务会立即执行,执行完成后才会继续向下执行
dispatch_sync(queue, ^{
NSLog(@"1--%@--",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2--%@--",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3--%@--",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"4--%@--",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"5--%@--",[NSThread currentThread]);
});
// 先将以上任务逐个依次执行完毕后才会执行这句话,并且多有任务的执行都在主线程里完成
NSLog(@"dispatch_sync--end -- %@--",[NSThread currentThread]);
// 1--<NSThread: 0x7fdc38f188d0>{number = 1, name = main}--
// 2--<NSThread: 0x7fdc38f188d0>{number = 1, name = main}--
// 3--<NSThread: 0x7fdc38f188d0>{number = 1, name = main}--
// 4--<NSThread: 0x7fdc38f188d0>{number = 1, name = main}--
// 5--<NSThread: 0x7fdc38f188d0>{number = 1, name = main}--
// dispatch_sync--end -- <NSThread: 0x7fdc38f188d0>{number = 1, name = main}--
}
- 串行队列+异步任务:创建新线程,但是只会创建一个新线程,所有的任务都是在这个子线程里执行,执行顺序按照添加任务 的先后顺序,并且不是立即执行,而是等整个方法
/*
* 串行队列+异步任务:创建新线程,但是只会创建一个新线程,所有的任务都是在这个子线程里执行,执行顺序按照添加任务 的先后顺序,并且不是立即执行,而是等整个方法
*/
- (void)serialAndAsync
{
// 创建一个串行队列
// 参数1:标识,一般用公司域名abc.com
// 参数2:队列类型:串行和并行两种
dispatch_queue_t queue = dispatch_queue_create("song.com", DISPATCH_QUEUE_SERIAL);
// 同步方式创建任务,任务会立即执行,执行完成后才会继续向下执行
dispatch_async(queue, ^{
NSLog(@"1--%@--",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2--%@--",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3--%@--",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"4--%@--",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"5--%@--",[NSThread currentThread]);
});
// 先将以上任务逐个依次执行完毕后才会执行这句话,并且多有任务的执行都在主线程里完成
NSLog(@"dispatch_async--end -- %@--",[NSThread currentThread]);
// dispatch_async--end -- <NSThread: 0x7f97f2611bf0>{number = 1, name = main}--
// 1--<NSThread: 0x7f97f24461b0>{number = 2, name = (null)}--
// 2--<NSThread: 0x7f97f24461b0>{number = 2, name = (null)}--
}
- 主队列 是GCD自带的一种特殊的串行队列
- dispatch_get_main_queue()
- 全局并发队列
- dispatch_get_global_queue(优先级,0)
全局并发队列的特性和手动创建的队列一样
- dispatch_get_global_queue(优先级,0)
- 主队列+异步任务:不会创建新线程,所有的任务都是在这个父线程里执行,执行顺序按照添加任务 的先后顺序,并且不是立即执行,而是等整个方法结束后依次执行
/*
* 主队列+异步任务:不会创建新线程,所有的任务都是在这个父线程里执行,执行顺序按照添加任务 的先后顺序,并且不是立即执行,而是等整个方法结束后依次执行 */
- (void)mainAndAsync
{
NSLog(@"dispatch_async--begin -- %@--",[NSThread currentThread]);
// 创建一个串行队列
// 参数1:标识,一般用公司域名abc.com
// 参数2:队列类型:串行和并行两种
dispatch_queue_t queue = dispatch_get_main_queue();;
// 异步方式创建任务,任务不会立即执行
dispatch_async(queue, ^{
NSLog(@"1--%@--",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2--%@--",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3--%@--",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"4--%@--",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"5--%@--",[NSThread currentThread]);
});
// 先将以上任务逐个依次执行完毕后才会执行这句话,并且多有任务的执行都在主线程里完成
NSLog(@"dispatch_get_main_queue--end -- %@--",[NSThread currentThread]);
}
- 主队列+同步任务:这个会产生问题,死锁,添加任务到主队列的任务要求立即执行,但是主队列是串行队列,当前任务要求执行完当前任务在执行新添加的任务。结果就是:两个任务互相等待,产生死锁
/*
* 主队列+同步任务:这个会产生问题,死锁,添加任务到主队列的任务要求立即执行,但是主队列是串行队列,当前任务要求执行完当前任务在执行新添加的任务。结果就是:两个任务互相等待,产生死锁
*/
- (void)mainAndSync
{
NSLog(@"dispatch_sync--begin -- %@--",[NSThread currentThread]);
// 创建一个串行队列
// 参数1:标识,一般用公司域名abc.com
// 参数2:队列类型:串行和并行两种
dispatch_queue_t queue = dispatch_get_main_queue();
// 同步方式创建任务,任务会立即执行,执行完成后才会继续向下执行
dispatch_sync(queue, ^{
NSLog(@"1--%@--",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2--%@--",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3--%@--",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"4--%@--",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"5--%@--",[NSThread currentThread]);
});
// 先将以上任务逐个依次执行完毕后才会执行这句话,并且多有任务的执行都在主线程里完成
NSLog(@"dispatch_get_main_queue--end -- %@--",[NSThread currentThread]);
}
截止执行
- dispatch_barrier_async :截断线程执行,以上两个任务完成后才会执行这个任务,并在完成barrier后继续执行下面的任务
- 任务1,2的执行始终在任务3,4之前
- 只有在并发队列中才有阶段功能
延时执行
- (void)delay
{
// 延时执行
NSLog(@"start--time:%@",[NSDate date]);
// NSObject 方法
[self performSelector:@selector(run) withObject:nil afterDelay:2];
// NSTimer
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(run) userInfo:nil repeats:NO];
// GCD
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"run--time:%@",[NSDate date]);
});
}
一次性代码
- 一次性代码内部默认就是线程安全的,不会出现多个线程同时访问内部代码
- (void)excuteOnce
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"只执行一次---%@",[NSThread currentThread]);
});
NSLog(@"excuteOnce--%@",[NSThread currentThread]);
}
快速迭代
// 快速迭代,顺序不确定
- (void)apply
{
dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {
NSLog(@"dispatch_apply--%ld--%@",index,[NSThread currentThread]);
});
}
队列组
/*
* 队列组:先执行async里的任务,最后执行notify任务
*/
- (void)groupAndAsync
{
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 先执行3个耗时操作
dispatch_group_async(group, queue, ^{
for (int i = 0 ; i < 1000; i ++) {
NSLog(@"1--%@--",[NSThread currentThread]);
}
});
dispatch_group_async(group, queue, ^{
for (int i = 0 ; i < 1000; i ++) {
NSLog(@"2--%@--",[NSThread currentThread]);
}
});
dispatch_group_async(group, queue, ^{
for (int i = 0 ; i < 1000; i ++) {
NSLog(@"3--%@--",[NSThread currentThread]);
}
});
// 等到以上任务完成后才会执行这个notify任务
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"main--%@--",[NSThread currentThread]);
});
}
NSOperation
- NSOperation是一抽象类,只能使用它的子类NSBlockOperation和NSInvocationOperation,或者自定义NSOperation。
1、NSInvocationOperation
- 使用方法initWithTarget:进行初始化。
- 默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作。
- 只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作。
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
[op start];
2、NSBlockOperation
- 使用blockOperationWithBlock添加任务,或者addExecutionBlock添加多个任务。
- 只要添加的任务数量大于1就会自动创建多个线程,异步执行。
NSBlockOperation *ope1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"0---%@",[NSThread currentThread]);
}];
[ope1 addExecutionBlock:^{
NSLog(@"1---%@",[NSThread currentThread]);
}];
[ope1 addExecutionBlock:^{
NSLog(@"2---%@",[NSThread currentThread]);
}];
[ope1 addExecutionBlock:^{
NSLog(@"3---%@",[NSThread currentThread]);
}];
[ope1 start];
3、NSOperationQueue
- NSOperation可以调用start方法来执行任务,但默认是同步执行的。
- 如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作。
// 添加到队列的任务会自动并发执行
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *ope1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1---%@",[NSThread currentThread]);
}];
NSBlockOperation *ope2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2---%@",[NSThread currentThread]);
}];
NSBlockOperation *ope3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"3---%@",[NSThread currentThread]);
}];
// 添加到队列会自动执行,不需要手动调用start方法
[queue addOperation:ope1];
[queue addOperation:ope2];
[queue addOperation:ope3];
[queue addOperationWithBlock:^{
NSLog(@"4---%@",[NSThread currentThread]);
}];
4、最大并发数
- 设置队列的最大并发数
- maxConcurrentOperationCount = 2;,同一时刻只会有两条线程在执行
- [queue setMaxConcurrentOperationCount:2]; // 这样设置
- 如果设置为1,就变成串行队列了
// 最大并发数,同一时刻只会有两条线程在执行
queue.maxConcurrentOperationCount = 2;
5、任务依赖 addDependency
- 多个线程之间可以建立依赖关系
// 添加依赖:任务1和2的执行在3之前
[ope3 addDependency:ope1];
[ope3 addDependency:ope2];
6、线程通信
- 获取主队列mainQueue,将任务添加到主队列
- 如果定义的时全局的队列,可以在其他地方向这个队列添加任务。
// 获取主队列
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"main---%@",[NSThread currentThread]);
}];
iOS笔记058 - IOS之多线程的更多相关文章
- iOS 面试常问之多线程
本片围绕多线程全面展开叙述. 1.为什么要有多线程/多线程是用来干什么的? 2.多线程是什么? 3.如何创建多线程? 4.多线程在哪些情况下会使用/多线程使用场景? 5.三种多线程的优缺点? 6.线程 ...
- 【iOS系列】-iOS的多线程解析
[iOS系列]-iOS的多线程解析 iOS的多线程实现技术: 1:GCD -- Grand Central Dispatch 是基于C语言的底层API 用Block定义任务,使用起来非常灵活便捷 提供 ...
- 荼菜的iOS笔记--UIView的几个Block动画
前言:我的第一篇文章荼菜的iOS笔记–Core Animation 核心动画算是比较详细讲了核心动画的用法,但是如你上篇看到的,有时我们只是想实现一些很小的动画,这时再用coreAnimation就会 ...
- 【IOS笔记】Event Delivery: The Responder Chain
Event Delivery: The Responder Chain 事件分发--响应链 When you design your app, it’s likely that you want t ...
- 【IOS笔记】About Events in iOS
About Events in iOS Users manipulate their iOS devices in a number of ways, such as touching the scr ...
- CCNA学习笔记(1) IOS操作系统 路由器 交换机 启动 自检 以及部分命令
注意:以下内容是以思科为学习环境 IOS操作系统启动: 路由和交换机和个人电脑启动没有区别,都会发送新号表示启动状态,也会进入系统自检.只得注意的是:1.一长两短的响声是显卡报警. 2.一声长鸣是内存 ...
- iOS开发 - 兼容iOS 10
1.Notification(通知) 自从Notification被引入之后,苹果就不断的更新优化,但这些更新优化只是小打小闹,直至现在iOS 10开始真正的进行大改重构,这让开发者也体会到UserN ...
- iOS 1 到 iOS 10 ,我都快老了
iOS 1:iPhone诞生 虽然很难想像,但初代iPhone在问世时在功能方面其实远远落后于那时的竞争对手,比如Windows Mobile.Palm OS.塞班.甚至是黑莓.它不支持3G.多任务. ...
- iOS面试必备-iOS基础知识
近期为准备找工作面试,在网络上搜集了这些题,以备面试之用. 插一条广告:本人求职,2016级应届毕业生,有开发经验.可独立开发,低薪求职.QQ:895193543 1.简述OC中内存管理机制. 答:内 ...
随机推荐
- 生理周期,POJ(1006)
题目链接:http://poj.org/problem?id=1006 解题报告: 1.枚举天数的时候可以根据前面的结果直接跳过一些错误的答案. ///三个周期是23,28,33, #include ...
- Mac下更新Vim到最新版本
目前,Mac内置的Vim是7.3版本的,而且还缺少很多功能,下面介绍如何通过源码安装更新最新版本的Vim,同时保留系统内置的Vim. # 下载Vim源代码 git clone https://gith ...
- 用c#语言编写水仙花数
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...
- 手把手教你玩转 CSS3 3D 技术
css3的3d起步 要玩转css3的3d,就必须了解几个词汇,便是透视(perspective).旋转(rotate)和移动(translate).透视即是以现实的视角来看屏幕上的2D事物,从而展现3 ...
- iOS 从0到1搭建高可用App框架
iOS 从0到1搭建高可用App框架 最近在搭建新项目的iOS框架,一直在思考如何才能搭建出高可用App框架,能否避免后期因为代码质量问题的重构.以前接手过许多“烂代码”,架构松散,底层混乱,缺少规范 ...
- qt项目:员工信息管理系统
开发一个员工信息管理系统 一.项目具体要求: 1.用qt开发界面,数据库用QSqlite 数据库文件名:demostudent.db 2.通过界面能够查看到数据库中员工信息表中内容,包括员工姓名.年龄 ...
- 『ACM C++』 PTA 天梯赛练习集L1 | 012-015
女神节快乐鸭,大学的女生节真的是忙碌呢,到处送礼物,真的是当时男生节的出来混的,总该是要还的hhhhh ------------------------------------------------ ...
- 内存分配---FF、BF、WF三种算法
动态分区分配是根据进程的实际需要,动态的为之分配内存空间.而在实现可变分区分配时,将涉及到分区分配中 所用的数据结构.分区分配算法和分区的分配与内存回收的过程. 分区分配中的数据结构:(1)描述空闲块 ...
- Centos防火墙的配置
Selinux的三种模式:enforcing,passive,disable 临时更改模式:setengorce 1|0 1:enforcing, 0:passive [root@C ...
- Java中的文件和stream流的操作代码
1.Java中FileRead方法的运用代码及详解 package example2;import java.io.FileReader;import java.io.IOException;clas ...