首页 文章 精选 留言 我的

精选列表

搜索[c ],共10000篇文章
优秀的个人博客,低调大师

C# 程序开发:设计模式之单例模式

1、定义:单例模式就是保证在整个应用程序的生命周期中,在任何时刻,被指定的类只有一个实例,并为客户程序提供一个获取该实例的全局访问点。 首先来明确一个问题,那就是在某些情况下,有些对象,我们只需要一个就可以了。 2、单例模式的优点有: (1)实例控制:单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。 (2)灵活性:因为类控制了实例化过程,所以类可以灵活更改实例化过程。 3、单例模式的缺点有: (1)开销:虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。 (2)可能的开发混淆:使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。 4、举个栗子: 一台计算机上可以连好几个打印机,但是这个计算机上的打印程序只能有一个,这里就可以通过单例模式来避免两个打印作业同时输出到打印机中,即在整个的打印过程中我只有一个打印程序的实例。其实生活中也有多类似的例子,比如操作ATM机的时候,存钱和取钱的操作是不能同时做的,只能一个一个来完成; 5.代码解析 第一种 最简单,但没有考虑线程安全,在多线程时可能会出问题.代码如下 解析如下: 1)首先,该Singleton的构造函数必须是私有的,以保证客户程序不会通过new()操作产生一个实例,达到实现单例的目的; 2)因为静态变量的生命周期跟整个应用程序的生命周期是一样的,所以可以定义一个私有的静态全局变量instance来保存该类的唯一实例; 3)必须提供一个全局函数访问获得该实例,并且在该函数提供控制实例数量的功能,即通过if语句判断instance是否已被实例化,如果没有则可以同new()创建一个实例;否则,直接向客户返回一个实例。 在这种经典模式下,没有考虑线程并发获取实例问题,即可能出现两个线程同时获取instance实例,且此时其为null时,就会出现两个线程分别创建了instance,违反了单例规则。因此,下面代码修改。 public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton GetInstance() { if(instance==null) { instance=new Singleton(); } return instance; } } 第二种 为多线程下的单例模式,考虑了线程安全,代码如下: 解析如下: 使用了双重锁方式较好地解决了多线程下的单例模式实现。先看内层的if语句块,使用这个语句块时,先进行加锁操作,保证只有一个线程可以访问该语句块,进而保证只创建了一个实例。 再看外层的if语句块,这使得每个线程欲获取实例时不必每次都得加锁,因为只有实例为空时(即需要创建一个实例),才需加锁创建,若果已存在一个实例,就直接返回该实例,节省了性能开销。 public class Singleton { private static Singleton instance; private static object _lock=new object(); private Singleton() { } public static Singleton GetInstance() { if(instance==null) { lock(_lock) { if(instance==null) { instance=new Singleton(); } } } return instance; } } 双if加lock保证多线程的唯一性。 第三种 饿汉模式 Eager Singleton(饿汉式单例类),其静态成员在类加载时就被初始化,此时类的私有构造函数被调用,单例类的唯一实例就被创建 这种模式的特点是自己主动实例,代码如下 使用的readonly关键可以跟static一起使用,用于指定该常量是类别级的,它的初始化交由静态构造函数实现,并可以在运行时编译。在这种模式下,无需自己解决线程安全性问题,CLR会给我们解决。由此可以看到这个类被加载时,会自动实例化这个类,而不用在第一次调用GetInstance()后才实例化出唯一的单例对象。 public sealed class Singleton { private static readonly Singleton instance=new Singleton(); private Singleton() { } public static Singleton GetInstance() { return instance; } } 第四种 懒汉模式 Lazy Singleton(懒汉式单例类),其类的唯一实例在真正调用时才被创建,而不是类加载时就被创建。所以Lazy Singleton不是线程安全的。 public class Singleton { private static Singleton singleton = null; public static synchronized Singleton getInstance(){ if(singleton==null){ singleton = new Singleton(); } return singleton; } } 总结: 单例中懒汉和饿汉的本质区别在于以下几点: 1、饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变。懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的。 2、从实现方式来讲他们最大的区别就是懒汉式是延时加载,他是在需要的时候才创建对象,而饿汉式在虚拟机启动的时候就会创建,饿汉式无需关注多线程问题,写法简单明了,能用则用。但是它是加载类时创建实例。所以如果是一个工厂模式,缓存了很多实例,那么就得考虑效率问题,因为这个类一加载则把所有实例不管用不用一块创建。 3、两者建立单例对象的时间不同。“懒汉式”是在你真正用到的时候才去建这个单例对象,“饿汉式”是在不管用不用得上,一开始就建立这个单例对象。 ok,今天的分享到这了,如果有疑问的可以留言,讲的不对的欢迎指出!!!

优秀的个人博客,低调大师

unity C# 常用算法 和 算法复杂度

1、稳定性 归并排序、冒泡排序、插入排序。基数排序是稳定的 选择排序、快速排序、希尔排序、堆排序是不稳定的 2、时间复杂度 最基础的四个算法:冒泡、选择、插入、快排中,快排的时间复杂度最小O(n*log2n),其他都是O(n2) 3.排序算法的思想: (1)冒泡排序: 是相邻元素之间的比较和交换,两重循环O(n2);所以,如果两个相邻元素相等,是不会交换的。所以它是一种稳定的排序方法 public void PopSort(int[] list) { int i, j, temp; //先定义一下要用的变量 for (i = 0; i < list.Length - 1; i++) { for (j = i + 1; j < list.Length; j++) { if (list[i] > list[j]) //如果第二个小于第一个数 { //交换两个数的位置,在这里你也可以单独写一个交换方法,在此调用就行了 temp = list[i]; //把大的数放在一个临时存储位置 list[i] = list[j]; //然后把小的数赋给前一个,保证每趟排序前面的最小 list[j] = temp; //然后把临时位置的那个大数赋给后一个 } } } } (2)选择排序: 每个元素都与第一个元素相比,产生交换,两重循环O(n2);举个栗子,5 8 5 2 9,第一遍之后,2会与5交换,那么原序列中两个5的顺序就被破坏了。所以不是稳定的排序算法 /// /// 选择排序 /// public class SelectionSorter { // public enum comp {COMP_LESS,COMP_EQUAL,COMP_GRTR}; private int min; // private int m=0; public void Sort(int[] list) { for (int i = 0; i < list.Length - 1; ++i) { min = i; for (int j = i + 1; j < list.Length; ++j) { if (list[j] < list[min]) min = j; } int t = list[min]; list[min] = list[i]; list[i] = t; // Console.WriteLine("{0}",list[i]); } } } (3)插入排序: 插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。刚开始这个小序列只包含第一个元素,事件复杂度O(n2)。比较是从这个小序列的末尾开始的。想要插入的元素和小序列的最大者开始比起,如果比它大则直接插在其后面,否则一直往前找它该插入的位置。如果遇见了一个和插入元素相等的,则把插入元素放在这个相等元素的后面。所以相等元素间的顺序没有改变,是稳定的。 /// /// 插入排序 /// public class InsertionSorter { public void Sort(int[] list) { for (int i = 1; i < list.Length; ++i) { int t = list[i]; int j = i; while ((j > 0) && (list[j - 1] > t)) { list[j] = list[j - 1]; --j; } list[j] = t; } } }

优秀的个人博客,低调大师

Objective-C中的associated object释放时机问题

如果对象A持有对象B,B作为A的associated object,并且表面上B没有其他被强引用的地方,那么对象A被释放时,对象B一定会同时释放吗?大部分情况下是,但真有不是的时候。最近实现代码的时候不小心就碰到了这样的特殊情况。 需求 需要监听对象A释放(dealloc)并执行对象A的a方法。此时引入对象B,并作为对象A的associated object。A释放时触发B释放,在B的dealloc方法中执行A的a方法。对象B需要一个指向对象A的属性,并声明为unsafe_unretained(或assign),因为weak指针此时已经失效了。 示例代码 @interface MyObject1 : NSObject @end @implementation MyObject1 - (void)foo { NSLog(@"success"); } @end @interface MyObject2 : NSObject @property (nonatomic, unsafe_unretained) MyObject1 *obj1; @end @implementation MyObject2 - (void)dealloc { [self.obj1 foo]; } + (instancetype)create { return [[self class] new]; } @end @implementation ViewController + (void)load { [self fun1]; } + (void)fun1 { MyObject1 *mo1 = [MyObject1 new]; @synchronized (self) { MyObject2 *mo2 = [MyObject2 create]; mo2.obj1 = mo1; objc_setAssociatedObject(mo1, @selector(viewDidLoad), mo2, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } } @end 问题 运行时出现崩溃,unsafe_unretained指针已经野了,和预期的不一样。堆栈是这样的: 观察崩溃的堆栈,发现mo2对象是被自动释放池释放了。因为mo1对象是在函数退出时就立即释放,这样导致mo1比mo2先被销毁,mo2访问了无效指针导致了崩溃。 这个问题和@synchronized有关系,但目前我还不知道它和arc之间有什么联系。下面给出另一个case,修改一行代码就不会崩溃了: + (void)fun2 { MyObject1 *mo1 = [MyObject1 new]; MyObject2 *mo2 = [MyObject2 create]; @synchronized (self) { mo2.obj1 = mo1; objc_setAssociatedObject(mo1, @selector(viewDidLoad), mo2, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } } 实际上只是把mo2的声明移动到了@synchronized外面,堆栈变成了这样: 这时,mo2的释放发生在调用方法的结束时。 分析 使用Hooper查看汇编代码,观察fun1和fun2的不同。节选出关键部分:fun1: fun2: 核心在于:fun1中,创建mo2后调用了retain,fun2中,调用的则是objc_retainAutoreleasedReturnValue。 我们再来看看create方法: 关键的一行在最后,调用了objc_autoreleaseReturnValue。 关于objc_retainAutoreleasedReturnValue和objc_autoreleaseReturnValue,请移步 https://www.jianshu.com/p/2f05060fa377 。大意是,这两个方法成对出现时,可以优化掉[[obj autorelease] retain]这种骚操作。 结论 在fun1中,由于没有objc_retainAutoreleasedReturnValue,取而代之的是retain,导致对象被放入自动释放池。对于@synchronized为什么会造成不同,我还没有那么深入。 因为全局自动释放池会延迟对象的释放,如果代码非常依赖对象的释放时机则会比较危险。我认为这样做是最保险的,创建一个局部自动释放池,保证局部变量在函数结束时立即释放: + (void)fun3 { MyObject1 *mo1 = [MyObject1 new]; @autoreleasepool { @synchronized (self) { MyObject2 *mo2 = [MyObject2 create]; mo2.obj1 = mo1; objc_setAssociatedObject(mo1, @selector(viewDidLoad), mo2, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } } } 参考资料 objc_autoreleaseReturnValue和objc_retainAutoreleasedReturnValue函数对ARC的优化 https://www.jianshu.com/p/2f05060fa377

优秀的个人博客,低调大师

Windows10 VS2017 C++信号处理

版权声明:本文可能为博主原创文章,若标明出处可随便转载。 https://blog.csdn.net/Jailman/article/details/85250506 #include "pch.h" #include <iostream> #include <csignal> #include <windows.h> using namespace std; int i; void signalHandle(int signum) { cout << "Interrupt signal(" << signum << ")received" << endl; i = signum; } int main() { //注册信号以及信号处理程序 signal(SIGINT, signalHandle); while (1) { if (i == 2) { break; } cout << "hello..." << endl; Sleep(1000);//暂停1s } system("pause"); return 0; } 参考https://blog.csdn.net/qq_28796345/article/details/51290493

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册