OC中: Thread: 使用简单方便,但效率不及下面的几种方式 NSOperationQueue:可以对thread的状态做精确的控制,gcd做不到 GCD: 效率做好的方案,且结合block,使用方便 pthread OS提供的api
首先理解线程同步
和互斥
的概念。
同步
在一个功能调用时,如果没有得到结果,调用就不返回
死锁
2个线程访问共享资源,顺序不当造成的。如一个线程锁定了资源A,想访问另一个线程锁定的资源B,而这个线程又在等待A资源。
线程同步
线程A和B一块配合,A执行到一定程度需要拷B的结果,于是停下来,等待B的指向结果。
- 临界区: 任意时刻只允许一个线程访问共享资源
- 互斥量: 拥有互斥对象的线程才能访问公共资源
- 信号量: 允许多个线程同时访问统一资源??
- 事件 : ?
结合代码来看看 linux上 3种 线程同步的方式:
pthread_mutex_t pthread_mutex_init() pthread_mutex_lock() // 在访问共享资源时,加锁,这样别的线程无法访问 pthread_mutex_unlock() // 解锁,这样别的线程可以访问共享资源了 pthread_mutex_destroy()// 释放互斥锁
互斥锁是如何通知到等待锁的线程的?
我猜内核会维护一个 互斥量对多个等待线程(1对多) 的表,在互斥量解锁后,采用某种方式选择一个等待线程唤醒,让其获得互斥锁,如此往复,直到所有等待线程唤醒执行。(具体待参加linux/kernel/mutex.c)
条件变量用来等待,阻塞一个线程,等待某个条件发生时触发。条件变量与互斥锁同时使用.
条件变量和互斥量相关联 是一种用于 多线程之间共享数据状态改变的通信机制。
pthread_cond_init() pthread_cond_destroy() pthread_cond_wait(cond,mutex) // 条件测试为假,线程就会阻塞; pthread_cond_signal() // 给出“条件成立”信号 pthread_cond_broadcast()
以生产者消费者问题为例,消费线程在得知队列中没有产品时,将阻塞自己; 生产者线程生产产品后,没有办法激活消费线程,这个时候生产者还要继续运行生产产品,不能用互斥量来实现;如果消费线程采用轮询的方式,无疑又是对CPU的浪费;最好的方式还是生产线程来唤醒消费线程;
那生产线程如何唤醒另一个线程呢?
条件变量本身是需要互斥量来保护的,也就是条件的检查实在互斥锁的保护下进行的。 因此pthread_cond_wait(cond,mutex)函数中,传递了一个mutex互斥量用来锁住cond条件变量
iOS中又NSCondition
- wait
- signal
- broadcast
NSCondition 还实现了 NSLocking协议
- lock
- unlock
又叫 信号灯
,本质上是一个计数器。
sem_t sem_init() // 初始化一个信号量,需要指定允许的最大资源计数。如果这里最大计数为1,跟互斥量类似了。 sem_wait() // 给信号量-1 , 如果信号量任然>=0,线程可以继续指向,否则等待 sem_post() // 给信号量+1 sem_destroy() // 销毁信号量
可以理解为,互斥量
是 信号量
的一种特殊情况(max_sem_count==1)
看下信号量的结构(/usr/src/linux/include/linux/sem.h) struct semaphore { spinlock_t lock; // 用来确保对count成员的原子操作 unsigned int count; struct list_head wait_list;// 在信号量+1,给wait的线程或进程发送信号量 };
线程互斥
: 某一资源同时只允许一个访问者访问。上面介绍的 互斥量
临界区
都可以实现线程的互斥
A线程 @synchronized(lockobj){ while([datas count==0){...} }
B线程 @synchronized(lockobj){ [datas addObject:[Item new]]; }
A线程一直在while循环上等待,但是B线程有无法获得lockobj锁而等待出现死锁。解决办法是用NSLock来替换@synchronized(lock),在while()中
1). 在使用锁的程序中,不要在程序中间使用return(这个时候还没有解锁,就可能会造成死锁), 而使用goto函数跳转至解锁并退出函数的位置
- 线程重排序reordering thread
- minimize locking
- a bigger loc
- try lock
- time out for locking
互斥量比临界区复杂,临界区只能完成统一进程内线程直接的同步,互斥量可以实现不同进程的线程的同步,可以跨进程使用。
互斥量,信号量,事件都可以跨进程访问
生产者和消费者之间通常有一个缓冲区作为中介。这个缓冲区有以下作用:
- 解耦合
- 让 生产者 和 消费者 并发执行
- 支持忙闲不均
队列缓冲区 环形缓冲区
实现一个队列。队列的应用场景为: 一个生产者线程将int类型的数入列,一个消费者线程将int类型的数出列
这也是一个非常经典的多线程题目,题目大意如下:有一个写者很多读者,多个读者可以同时读文件,但写者在写文件时不允许有读者在读文件,同样有读者读时写者也不能写。
主线程启动10个子线程并将表示子线程序号的变量地址作为参数传递给子线程。子线程接收参数 -> sleep(50) -> 全局变量++ -> sleep(0) -> 输出参数和全局变量。
要求: 1.子线程输出的线程序号不能重复。 2.全局变量的输出必须递增。
编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推。
有四个线程1、2、3、4。线程1的功能就是输出1,线程2的功能就是输出2,以此类推.........现在有四个文件ABCD。初始都为空。现要让四个文件呈如下格式:
A:1 2 3 4 1 2.... B:2 3 4 1 2 3.... C:3 4 1 2 3 4.... D:4 1 2 3 4 1....
请设计程序。