利用操作队列和信号量来实现操作同步

移动开发 iOS
最近在开发iOS过程中遇到一个问题:某一些操作需要在一个初始化操作后才允许执行。但是这些操作的执行时刻有可能比初始化操作来得要快。那么,如果不等待初始化操作后再执行的话,这些操作就等于是丢失了。

最近在开发iOS过程中遇到一个问题:某一些操作需要在一个初始化操作后才允许执行。但是这些操作的执行时刻有可能比初始化操作来得要快。那么,如果不等待初始化操作后再执行的话,这些操作就等于是丢失了。

针对这个问题,我想到了两种解决方案:***就是执行这些操作之前先判断是否已经初始化,如果尚未初始化则使用一个数组队列把操作参数及调用的方法存储起来,等待初始化完成后再检测数组队列中的保存的操作进行调用并清空队列。但这种方式有个问题就是操作中传递的参数以及调用方法引用都需要自己来维护,这无疑是给自己带来了一定的工作量以及风险,稍有不慎就有可能会导致内存泄露。

因此第二中解决方法就是利用串行队列结合信号量的方式来控制操作的执行。此方案的思路是,先创建一条串行队列,此队列用于执行所有的操作。但是***入队的是一个等待信号的操作。而这个信号的初始值是0,直到初始化操作完成后才会发送一个信号来通知此操作。因此,在尚未初始化完成的时候此队列是一直处于阻塞状态的。所以到有操作进入队列时都会立刻执行,而是需要等到初始化信号过来后才开始执行。

为了验证这一想法,我新建了一个应用工程,在ViewController中定义了操作队列_quque和信号量_sema,如下:

  1. @interface ViewController : UIViewController   
  2.  
  3.  {   
  4.  
  5.  @private  
  6.  
  7.      dispatch_queue_t _queue;   
  8.  
  9.      dispatch_semaphore_t _sema;   
  10.  
  11.  }   
  12.     
  13.  
  14. @end  

初始化时创建操作队列

  1. - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil   
  2.  
  3.  {   
  4.  
  5.      if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])   
  6.  
  7.      {   
  8.  
  9.          _queue = dispatch_queue_create("cn.vimfung.demo", DISPATCH_QUEUE_SERIAL);   
  10.  
  11.     }   
  12.  
  13.          
  14.  
  15.      return self;   
  16.  
  17.  }  

在ViewController中定义了三个按钮,分别为DoSomething、Signal、Wait。其中DoSomething为执行的操作。Signal为通知阻塞队列可以执行操作了。Wait为阻塞当前队列。

  1. - (void)viewDidLoad   
  2.  
  3.  {   
  4.  
  5.      [super viewDidLoad];   
  6.  
  7.      // Do any additional setup after loading the view, typically from a nib.   
  8.  
  9.          
  10.  
  11.      UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];   
  12.  
  13.      [btn setTitle:@"DoSomething" forState:UIControlStateNormal];   
  14.  
  15.      [btn sizeToFit];   
  16.  
  17.      [btn addTarget:self action:@selector(doSomethingHandler:) forControlEvents:UIControlEventTouchUpInside];   
  18.  
  19.      [self.view addSubview:btn];   
  20.  
  21.          
  22.  
  23.      UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];   
  24.  
  25.      [btn1 setTitle:@"Signal" forState:UIControlStateNormal];   
  26.  
  27.      [btn1 sizeToFit];   
  28.  
  29.      [btn1 addTarget:self action:@selector(signalHanlder:) forControlEvents:UIControlEventTouchUpInside];   
  30.  
  31.      btn1.frame = CGRectMake(0.0, 50.0, btn1.frame.size.width, btn1.frame.size.height);   
  32.  
  33.      [self.view addSubview:btn1];   
  34.  
  35.          
  36.  
  37.      UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];   
  38.  
  39.      [btn2 setTitle:@"Wait" forState:UIControlStateNormal];   
  40.  
  41.      [btn2 sizeToFit];   
  42.  
  43.      [btn2 addTarget:self action:@selector(waitHanlder:) forControlEvents:UIControlEventTouchUpInside];   
  44.  
  45.      btn2.frame = CGRectMake(0.0, 100.0, btn2.frame.size.width, btn2.frame.size.height);   
  46.  
  47.      [self.view addSubview:btn2];   
  48.  
  49.  }   
  50.  
  51.      
  52.  
  53.  - (void)doSomethingHandler:(id)sender   
  54.  
  55.  {   
  56.  
  57.      dispatch_async(_queue, ^{   
  58.  
  59.         NSLog(@"do something");   
  60.  
  61.      });   
  62.  
  63.  }   
  64.  
  65.      
  66.  
  67.  - (void)signalHanlder:(id)sender   
  68.  
  69.  {   
  70.  
  71.      dispatch_semaphore_signal(_sema);   
  72.  
  73.  }   
  74.  
  75.      
  76.  
  77.  - (void)waitHanlder:(id)sender   
  78.  
  79.  {   
  80.  
  81.      if (_sema)   
  82.  
  83.     {   
  84.  
  85.          dispatch_release(_sema);   
  86.  
  87.      }   
  88.  
  89.     _sema = dispatch_semaphore_create(0);   
  90.  
  91.     dispatch_async(_queue, ^{   
  92.  
  93.          dispatch_semaphore_wait(_sema, DISPATCH_TIME_FOREVER);   
  94.  
  95.      });   
  96.  
  97.  } 

运行后,先点击Wait让队列阻塞、然后这时无论怎么点击DoSomething都是不会有log信息显示,直到点击Signal后,之前点击的DoSomething将会一一打印出来信息。

可见这种解决方案是可行的,并且可以更加容易操作。

责任编辑:张叶青 来源: 开源社区
相关推荐

2010-04-21 16:42:48

Unix信号量

2010-07-15 15:32:10

Perl线程

2021-04-13 09:20:15

鸿蒙HarmonyOS应用开发

2020-11-05 09:59:24

Linux内核信号量

2010-04-21 16:50:31

Unix信号量

2017-05-11 14:05:25

Consul分布式信号量

2010-04-21 15:37:38

Unix信号量

2020-09-25 07:34:40

Linux系统编程信号量

2021-09-07 07:53:42

Semaphore 信号量源码

2010-04-21 16:25:13

Unix信号量

2016-11-23 16:08:24

Python处理器分布式系统

2019-11-19 09:00:38

JavaAND信号量

2010-04-21 17:10:25

Unix信号量

2010-03-17 16:36:10

Java信号量模型

2009-12-08 12:14:43

2010-03-16 17:52:27

Java多线程信号量

2021-02-03 20:10:29

Linux信号量shell

2020-11-10 15:25:26

SemaphoreLinux翻译

2023-11-23 08:31:51

竞争锁共享字段

2021-05-18 06:55:07

Java AQS源码
点赞
收藏

51CTO技术栈公众号