iOS-GCD多线程编程详解6


iOS-GCD多线程编程详解6


这篇主要讲的函数是dispatch_semaphore的dispatch_semaphore_create,dispatch_semaphore_wait,dispatch_semaphore_signal函数的使用。dispatch_semaphore_t 的作用是异步多线程的信号传递来达到多线程的依赖执行,说白了就是通过信号来在多线程中传递来达到线程是否继续执行的条件,线程通过信号来决定是否继续执行,下面来看具体的使用及说明。


一.dispatch_semaphore_t函数说明

1.dispatch_semaphore_t  dispatch_semaphore_create(long value)-》该函数的作用是创建一个dispatch_semaphore_t的信号变量,传人的参数为long int 类型的value, 当value的值传人0主要用于两个线程对一个特定的事件要保持一致性。传人大于0 的数主要用于管理有限个资源池,池中资源的数量等于传人的value。

2.long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);该函数的作用是为了在该线程中等待信号,当timeout的时间到了,就会执行该线程中的指令。传人的dsema为dispatch_semaphore_t的变量,timeout为等待的时间,如果timeout时间到了就会执行该线程下面的指令。返回值为long类型,如果返回值为0表示执行完成,如果为非0表示超时。读者可以通过返回值来判断来执行不同情况的代码。

3.long dispatch_semaphore_signal(dispatch_semaphore_t dsema);该函数为增加信号量,返回值类型为long类型,当为0时表示线程在执行block,非0 表示block任务等待状态。传人的参数为信号量。

二.函数各种组合及结果分析

第一种不使用dispatch_semaphore_t的异步调用:

dispatch_queue_t queue = dispatch_queue_create("My_QUEUE", NULL);
    
    dispatch_async(queue, ^{
        NSLog(@"异步线程%@",[NSThread currentThread]);
    });
    
    NSLog(@"主线程%@",[NSThread currentThread]);

运行结果:

1.

2015-01-10 17:58:31.219 GCDTest[1699:93299] 主线程<NSThread: 0x7fe190e27910>{number = 1, name = main}

2015-01-10 17:58:31.219 GCDTest[1699:93346] 异步线程<NSThread: 0x7fe190d06d60>{number = 2, name = (null)}

2.

2015-01-10 18:00:07.940 GCDTes[1709:94085] 主线程<NSThread: 0x7f9620d27cf0>{number = 1, name = main}

2015-01-10 18:00:07.940 GCDTest[1709:94138] 异步线程<NSThread: 0x7f9620e18100>{number = 2, name = (null)}

结果分析:

主线程的优先级别比异步线程的优先级别高,所以它的运行时间片比异步线程多,所以主线程先输出。

第二种使用情况,加入dispatch_semaphore_t    等待时间为10秒

dispatch_queue_t queue = dispatch_queue_create("My_QUEUE", NULL);//创建一个队列
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);//创建一个信号量
    
    dispatch_async(queue, ^{        //异步执行一个线程
        
        NSLog(@"异步线程%@",[NSThread currentThread]);
    
      long int threadState =  dispatch_semaphore_signal(sema);   //获得该block是否被执行的状态
        if (threadState) {
            NSLog(@"该线程unwoken%@",[NSThread currentThread]);
        }else{
            NSLog(@"该线程woken%@",[NSThread currentThread]);
        }
        
        dispatch_semaphore_signal(sema);
    });
    
    long int state  = dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, 10000000000));
    if(state){              //判断时超时了还是正常的执行完成超时时间为10秒
        NSLog(@"超时");
    }else{
        NSLog(@"执行成功");
    }
    
    NSLog(@"主线程%@",[NSThread currentThread]);


运行结果:

1.

2015-01-10 18:18:01.847 GCDTest[1969:102210] 异步线程<NSThread: 0x7fcfe9d2e380>{number = 2, name = (null)}

2015-01-10 18:18:01.848 GCDTest[1969:102210] 该线程unwoken<NSThread: 0x7fcfe9d2e380>{number = 2, name = (null)}

2015-01-10 18:18:01.848 GCDTest[1969:102182] 执行成功

2015-01-10 18:18:01.848 GCDTest[1969:102182] 主线程<NSThread: 0x7fcfe9d25250>{number = 1, name = main}

2.

2015-01-10 18:27:34.153 GCDTest[1999:104402] 异步线程<NSThread: 0x7ffd48e32dd0>{number = 2, name = (null)}

2015-01-10 18:27:34.153 GCDTest[1999:104370] 执行成功

2015-01-10 18:27:34.153 GCDTest[1999:104402] 该线程unwoken<NSThread: 0x7ffd48e32dd0>{number = 2, name = (null)}

2015-01-10 18:27:34.154 GCDTest[1999:104370] 主线程<NSThread: 0x7ffd48f14ab0>{number = 1, name = main}


结果分析,说明当主线程的优先级别比较高,当主线程分离出一个异步线程时,异步线程处于等待状态,主线程往下执行遇到dispatch_semaphore_wait

函数,于是就等待10秒钟,这时异步线程获得了运行时间片,因为主线程在等待信号量是线程时挂起状态,所以输出unwoken,因为主线程等待了10秒钟,在这十秒钟内异步线程执行完成了所以输出“执行完成”,之后在执行主线程下面的内容。

第三种使用情况,加入dispatch_semaphore_t    等待时间为十亿分之一秒

dispatch_queue_t queue = dispatch_queue_create("My_QUEUE", NULL);//创建一个队列
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);//创建一个信号量
    
    dispatch_async(queue, ^{        //异步执行一个线程
        
        NSLog(@"异步线程%@",[NSThread currentThread]);
    
        long int threadState =  dispatch_semaphore_signal(sema);   //获得该block是否被执行的状态
        if (threadState) {
            NSLog(@"该线程unwoken%@",[NSThread currentThread]);
        }else{
            NSLog(@"该线程woken%@",[NSThread currentThread]);
        }
        
        dispatch_semaphore_signal(sema);
    });
    
    long int state  = dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, 1));
    if(state){              //判断时超时了还是正常的执行完成超时时间为10 亿分之 1秒
        NSLog(@"超时");
    }else{
        NSLog(@"执行成功");
    }
    
    NSLog(@"主线程%@",[NSThread currentThread]);

运行结果:

1.

2015-01-10 18:32:31.503 GCDTest[2123:107351] 异步线程<NSThread: 0x7fc12a70f790>{number = 2, name = (null)}

2015-01-10 18:32:31.503 GCDTest[2123:107326] 超时

2015-01-10 18:32:31.504 GCDTest[2123:107351] 该线程woken<NSThread: 0x7fc12a70f790>{number = 2, name = (null)}

2015-01-10 18:32:31.504 GCDTest[2123:107326] 主线程<NSThread: 0x7fc12a416a70>{number = 1, name = main}

2.

2015-01-10 18:32:49.667 GCDTest[2129:107629] 超时

2015-01-10 18:32:49.667 GCDTest[2129:107657] 异步线程<NSThread: 0x7fa139c7aa80>{number = 2, name = (null)}

2015-01-10 18:32:49.667 GCDTest[2129:107657] 该线程woken<NSThread: 0x7fa139c7aa80>{number = 2, name = (null)}

2015-01-10 18:32:49.667 GCDTest[2129:107629] 主线程<NSThread: 0x7fa139c29310>{number = 1, name = main}

3.

2015-01-10 18:33:12.352 GCDTest[2134:107906] 异步线程<NSThread: 0x7ff75a63d8b0>{number = 2, name = (null)}

2015-01-10 18:33:12.353 GCDTest[2134:107906] 该线程woken<NSThread: 0x7ff75a63d8b0>{number = 2, name = (null)}

2015-01-10 18:33:12.352 GCDTest[2134:107878] 超时

2015-01-10 18:33:12.354 GCDTest[2134:107878] 主线程<NSThread: 0x7ff75a413490>{number = 1, name = main}

4.

2015-01-10 18:34:23.583 GCDTest[2141:108330] 超时

2015-01-10 18:34:23.584 GCDTest[2141:108330] 主线程<NSThread: 0x7fdde8426f30>{number = 1, name = main}

2015-01-10 18:34:23.583 GCDTest[2141:108369] 异步线程<NSThread: 0x7fdde8704cf0>{number = 2, name = (null)}

2015-01-10 18:34:23.584 GCDTest[2141:108369] 该线程woken<NSThread: 0x7fdde8704cf0>{number = 2, name = (null)}

5.

2015-01-10 18:34:59.629 GCDTest[2151:108851] 超时

2015-01-10 18:34:59.629 GCDTest[2151:108878] 异步线程<NSThread: 0x7ff142f276c0>{number = 2, name = (null)}

2015-01-10 18:34:59.630 GCDTest[2151:108851] 主线程<NSThread: 0x7ff142f06520>{number = 1, name = main}

2015-01-10 18:34:59.630 GCDTest[2151:108878] 该线程woken<NSThread: 0x7ff142f276c0>{number = 2, name = (null)}


运行结果分析,在主线程的时间片时当遇到信号等待函数是,又由于线程的时间片的随机性,所以主线程可能继续执行也可能挂起执行异步线程等多种情况,所以就会出现随机的输出结果。

第四种情况主线程没有遇到dispatch_semaphore_wait之前让主线程睡5秒钟。

dispatch_queue_t queue = dispatch_queue_create("My_QUEUE", NULL);//创建一个队列
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);//创建一个信号量
    
    dispatch_async(queue, ^{        //异步执行一个线程
        
        NSLog(@"异步线程%@",[NSThread currentThread]);
    
        long int threadState =  dispatch_semaphore_signal(sema);   //获得该block是否被执行的状态
        if (threadState) {
            NSLog(@"该线程unwoken%@",[NSThread currentThread]);
        }else{
            NSLog(@"该线程woken%@",[NSThread currentThread]);
        }
       
        
    });
    
    [NSThread sleepForTimeInterval:5];//睡5秒钟
    
    long int state  = dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, 1));
    if(state){              //判断时超时了还是正常的执行完成超时时间为10 亿分之 1秒
        NSLog(@"超时");
    }else{
        NSLog(@"执行成功");
    }
    
    NSLog(@"主线程%@",[NSThread currentThread]);

运行结果:

1:

2015-01-10 18:46:55.760 GCDTest[2304:113183] 异步线程<NSThread: 0x7faa117142d0>{number = 2, name = (null)}

2015-01-10 18:46:55.761 GCDTest[2304:113183] 该线程woken<NSThread: 0x7faa117142d0>{number = 2, name = (null)}

//相差5秒钟

2015-01-10 18:47:00.761 GCDTest[2304:113117] 执行成功

2015-01-10 18:47:00.761 GCDTest[2304:113117] 主线程<NSThread: 0x7faa11414140>{number = 1, name = main}

主线程没有遇到dispatch_semaphore_wait函数就睡着了,于是异步线程执行,异步线程执行完成之后主线程继续执行,所以输出结果不变。


第五种使用情况:

dispatch_semaphore_signal函数在任务开始前调用
<pre name="code" class="objc">dispatch_queue_t queue = dispatch_queue_create("My_QUEUE", NULL);//创建一个队列
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);//创建一个信号量
    
    dispatch_async(queue, ^{        //异步执行一个线程
        dispatch_semaphore_signal(sema);//在循环之前
        for (int i=0; i<4; i++) {
            NSLog(@"异步线程%@",[NSThread currentThread]);
        }

    });
    
    
    
    long int state  = dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, 1000000000));
    if(state){              //判断时超时了还是正常的执行完成超时时间为10 亿分之 1秒
        NSLog(@"超时");
    }else{
        NSLog(@"执行成功");
    }
    
    NSLog(@"主线程%@",[NSThread currentThread]);


运行结果:
1.<p class="p1"><span class="s1"><strong>2015-01-10 19:05:34.610 GCDTest[2599:121079] </strong></span><span class="s2"><strong>异步线程</strong></span><span class="s1"><strong><NSThread: 0x7ff258718d00>{number = 2, name = (null)}</strong></span></p><p class="p1"><span class="s1"><strong>2015-01-10 19:05:34.610 GCDTest[2599:121044] </strong></span><span class="s2"><strong>执行成功</strong></span></p><p class="p1"><span class="s1"><strong>2015-01-10 19:05:34.611 GCDTest[2599:121044] </strong></span><span class="s2"><strong>主线程</strong></span><span class="s1"><strong><NSThread: 0x7ff258600370>{number = 1, name = main}</strong></span></p><p class="p1"><span class="s1"><strong>2015-01-10 19:05:34.611 GCDTest[2599:121079] </strong></span><span class="s2"><strong>异步线程</strong></span><span class="s1"><strong><NSThread: 0x7ff258718d00>{number = 2, name = (null)}</strong></span></p><p class="p1"><span class="s1"><strong>2015-01-10 19:05:34.611 GCDTest[2599:121079] </strong></span><span class="s2"><strong>异步线程</strong></span><span class="s1"><strong><NSThread: 0x7ff258718d00>{number = 2, name = (null)}</strong></span></p><p class="p1"><span class="s1"><strong>2015-01-10 19:05:34.611 GCDTest[2599:121079] </strong></span><span class="s2"><strong>异步线程</strong></span><span class="s1"><strong><NSThread: 0x7ff258718d00>{number = 2, name = (null)}</strong></span></p><p class="p1"><span class="s1"><strong>2.</strong></span></p><p class="p1"><span class="s1"><strong></strong></span></p><p class="p1"><span class="s1"><strong>2015-01-10 19:05:57.101 GCDTest[2607:121357] </strong></span><span class="s2"><strong>执行成功</strong></span></p><p class="p1"><span class="s1"><strong>2015-01-10 19:05:57.102 GCDTest[2607:121395] </strong></span><span class="s2"><strong>异步线程</strong></span><span class="s1"><strong><NSThread: 0x7fb4c3721a50>{number = 2, name = (null)}</strong></span></p><p class="p1"><span class="s1"><strong>2015-01-10 19:05:57.102 GCDTest[2607:121395] </strong></span><span class="s2"><strong>异步线程</strong></span><span class="s1"><strong><NSThread: 0x7fb4c3721a50>{number = 2, name = (null)}</strong></span></p><p class="p1"><span class="s1"><strong>2015-01-10 19:05:57.102 GCDTest[2607:121357] </strong></span><span class="s2"><strong>主线程</strong></span><span class="s1"><strong><NSThread: 0x7fb4c3707140>{number = 1, name = main}</strong></span></p><p class="p1"><span class="s1"><strong>2015-01-10 19:05:57.103 GCDTest[2607:121395] </strong></span><span class="s2"><strong>异步线程</strong></span><span class="s1"><strong><NSThread: 0x7fb4c3721a50>{number = 2, name = (null)}</strong></span></p><p class="p1"><span class="s1"><strong>2015-01-10 19:05:57.103 GCDTest[2607:121395] </strong></span><span class="s2"><strong>异步线程</strong></span><span class="s1"><strong><NSThread: 0x7fb4c3721a50>{number = 2, name = (null)}</strong></span></p>3.

2015-01-10 19:06:14.510 GCDTest[2612:121617] 异步线程<NSThread: 0x7fc2ab683410>{number = 2, name = (null)}

2015-01-10 19:06:14.510 GCDTest[2612:121591] 执行成功

2015-01-10 19:06:14.511 GCDTest[2612:121617] 异步线程<NSThread: 0x7fc2ab683410>{number = 2, name = (null)}

2015-01-10 19:06:14.511 GCDTest[2612:121591] 主线程<NSThread: 0x7fc2ab610ad0>{number = 1, name = main}

2015-01-10 19:06:14.511 GCDTest[2612:121617] 异步线程<NSThread: 0x7fc2ab683410>{number = 2, name = (null)}

2015-01-10 19:06:14.511 GCDTest[2612:121617] 异步线程<NSThread: 0x7fc2ab683410>{number = 2, name = (null)}

运行结果分析:总是运行成功的因为你通过dispatch_semaphore_signal把信号传出去了,主线成就知道执行完成,还没有等待10秒钟就开始运行了,这时主线程得到运行时间片,而异步线程就挂起,之后就是一般的异步执行了。

第六种使用情况:dispatch_semaphore_signal在循环后面调用

dispatch_queue_t queue = dispatch_queue_create("My_QUEUE", NULL);//创建一个队列
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);//创建一个信号量
    
    dispatch_async(queue, ^{        //异步执行一个线程
        
        for (int i=0; i<4; i++) {
            NSLog(@"异步线程%@",[NSThread currentThread]);
        }
        dispatch_semaphore_signal(sema);//在循环之后
    });
    
    
    
    long int state  = dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, 1000000000));
    if(state){              //判断时超时了还是正常的执行完成超时时间为10 亿分之 1秒
        NSLog(@"超时");
    }else{
        NSLog(@"执行成功");
    }
    
    NSLog(@"主线程%@",[NSThread currentThread]);


运行结果:

运行结果:

2015-01-10 19:09:33.073 GCDTest[2630:122603] 异步线程<NSThread: 0x7fe7a94090e0>{number = 2, name = (null)}

2015-01-10 19:09:33.073 GCDTest[2630:122603] 异步线程<NSThread: 0x7fe7a94090e0>{number = 2, name = (null)}

2015-01-10 19:09:33.073 GCDTest[2630:122603] 异步线程<NSThread: 0x7fe7a94090e0>{number = 2, name = (null)}

2015-01-10 19:09:33.074 GCDTest[2630:122603] 异步线程<NSThread: 0x7fe7a94090e0>{number = 2, name = (null)}

2015-01-10 19:09:33.074 GCDTest[2630:122560] 执行成功

2015-01-10 19:09:33.074 GCDTest[2630:122560] 主线程<NSThread: 0x7fe7a970fe80>{number = 1, name = main}

结果分析:因为
dispatch_semaphore_signal在循环之后,主线程就等待,当循环执行完成之后调用<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;">dispatch_semaphore_signal通知主线程任务执行完成,于是主线才执行,如果等了10秒钟还没有收到信号,它就会按照超时处理。</span>
<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">	</span>总结:在程序设计时要把握信号的发送时间,因为信号是告诉别人你完成了,如果没有完成就发送信号,别的线程就会认为是完成而不是超时,编程中主要注意信号发送和等待的时间设置。</span>
<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">	</span>文明转载评论是对自己的尊重和对学者的鼓励,欢迎讨论指正。</span>
<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;">
</span>
posted @ 2015-01-10 16:58  fineman  阅读(221)  评论(0编辑  收藏  举报