互斥锁与信号量区别:
信号量的另一种形式,它允许在条件真的时候线程间相互发送信号(signal,这个也是和Lock锁区别之一)。条件和互斥锁的区别在于多个线程被允许同时访问一个条件。但是对于同一时间,互斥锁只能被一个线程访问
synchronized (防止不同线程在同一时间获取同一个锁)
@synchronized (anObj) ,如果每次在线程传递的不同的对象给anObj,那么每次他都将拥有他的锁,并持续处理,而不被其他线程阻塞。如果传递的是同一参数,那么该线程被阻塞,直到前一个线程解锁后,才能继续处理
Table 4-1 Lock types
Lock |
Description |
Mutex [互斥锁] |
A mutually exclusive (or mutex) lock acts as a protective barrier around a resource. A mutex is a type of semaphore that grants access to only one thread at a time. If a mutex is in use and another thread tries to acquire it, that thread blocks until the mutex is released by its original holder. If multiple threads compete for the same mutex, only one at a time is allowed access to it. |
Recursive lock [递归锁] |
A recursive lock is a variant on the mutex lock. A recursive lock allows a single thread to acquire the lock multiple times before releasing it. Other threads remain blocked until the owner of the lock releases the lock the same number of times it acquired it. Recursive locks are used during recursive iterations primarily but may also be used in cases where multiple methods each need to acquire the lock separately. |
Read-write lock |
A read-write lock is also referred to as a shared-exclusive lock. This type of lock is typically used in larger-scale operations and can significantly improve performance if the protected data structure is read frequently and modified only occasionally. During normal operation, multiple readers can access the data structure simultaneously. When a thread wants to write to the structure, though, it blocks until all readers release the lock, at which point it acquires the lock and can update the structure. While a writing thread is waiting for the lock, new reader threads block until the writing thread is finished. The system supports read-write locks using POSIX threads only. For more information on how to use these locks, see the pthread man page. |
Distributed lock |
A distributed lock provides mutually exclusive access at the process level. Unlike a true mutex, a distributed lock does not block a process or prevent it from running. It simply reports when the lock is busy and lets the process decide how to proceed. |
Spin lock |
A spin lock polls its lock condition repeatedly until that condition becomes true. Spin locks are most often used on multiprocessor systems where the expected wait time for a lock is small. In these situations, it is often more efficient to poll than to block the thread, which involves a context switch and the updating of thread data structures. The system does not provide any implementations of spin locks because of their polling nature, but you can easily implement them in specific situations. For information on implementing spin locks in the kernel, see Kernel Programming Guide. |
Double-checked lock |
A double-checked lock is an attempt to reduce the overhead of taking a lock by testing the locking criteria prior to taking the lock. Because double-checked locks are potentially unsafe, the system does not provide explicit support for them and their use is discouraged.[注意系统不显式支持该锁类型] |
Table 4-2 Mutex and atomic operation costs
Item |
Approximate cost |
Notes |
Mutex acquisition time |
Approximately 0.2 microseconds |
This is the lock acquisition time in an uncontested case. If the lock is held by another thread, the acquisition time can be much greater. The figures were determined by analyzing the mean and median values generated during mutex acquisition on an Intel-based iMac with a 2 GHz Core Duo processor and 1 GB of RAM running Mac OS X v10.5. |
Atomic compare-and-swap |
Approximately 0.05 microseconds |
This is the compare-and-swap time in an uncontested case. The figures were determined by analyzing the mean and median values for the operation and were generated on an Intel-based iMac with a 2 GHz Core Duo processor and 1 GB of RAM running Mac OS X v10.5. |
NSLock* arrayLock = [self GetArrayLock];
NSMutableArray* myArray = GetSharedArray();
id anObject;
[arrayLock lock];
anObject = [myArray objectAtIndex:0];
[arrayLock unlock];
// 在处理doSomething的时候共享资源myArray可能被修改,下面的操作就是有风险的操作
[anObject doSomething];
NSMutableArray* myArray = GetSharedArray();
id anObject;
[arrayLock lock];
anObject = [myArray objectAtIndex:0];
// 在处理doSomething放到Lock里面,如果doSomething处理时间比较长,那么就形成了效率瓶颈,影响程序效率
[anObject doSomething];
[arrayLock unlock];
NSLock* arrayLock = [self GetArrayLock];
NSMutableArray* myArray = GetSharedArray();
id anObject;
[arrayLock lock];
anObject = [myArray objectAtIndex:0];
// 把对象retain and save,防止在unlock,myArray里面的内容被修改
[anObject retain];
[arrayLock unlock];
[anObject doSomething];
[anObject release];
4,当心死锁(DeadLock)和活锁(LiveLock)
任何线程试图同时获得多于一个锁,就有可能发生死锁的可能。当两个线程分别保持一个锁,A线程-A锁/B线程-B锁
避免死锁和活锁的最好方法是同一时间只拥有一个锁
5,正确使用volatile变量
关键字volatile只确保每次获取volatile变量时都是从内存加载变量,而不是使用寄存器里面的值,他不保证代码访问变量是正确的
Table 4-3 Atomic math and logic operations
Operation |
Function name |
Description |
Add |
OSAtomicAdd32 |
Adds two integer values together and stores the result in one of the specified variables. |
Increment |
OSAtomicIncrement32 |
Increments the specified integer value by 1. |
Decrement |
OSAtomicDecrement32 |
Decrements the specified integer value by 1. |
Logical OR |
OSAtomicOr32 |
Performs a logical OR between the specified 32-bit value and a 32-bit mask. |
Logical AND |
OSAtomicAnd32 |
Performs a logical AND between the specified 32-bit value and a 32-bit mask. |
Logical XOR |
OSAtomicXor32 |
Performs a logical XOR between the specified 32-bit value and a 32-bit mask. |
Compare and swap |
OSAtomicCompareAndSwap32 |
Compares a variable against the specified old value. If the two values are equal, this function assigns the specified new value to the variable; otherwise, it does nothing. The comparison and assignment are done as one atomic operation and the function returns a Boolean value indicating whether the swap actually occurred. |
Test and set |
OSAtomicTestAndSet |
Tests a bit in the specified variable, sets that bit to 1, and returns the value of the old bit as a Boolean value. Bits are tested according to the formula (0×80 >> (n & 7)) of byte((char*)address + (n >> 3)) where n is the bit number and address is a pointer to the variable. This formula effectively breaks up the variable into 8-bit sized chunks and orders the bits in each chunk in reverse. For example, to test the lowest-order bit (bit 0) of a 32-bit integer, you would actually specify 7 for the bit number; similarly, to test the highest order bit (bit 32), you would specify 24 for the bit number. |
Test and clear |
OSAtomicTestAndClear |
Tests a bit in the specified variable, sets that bit to 0, and returns the value of the old bit as a Boolean value. Bits are tested according to the formula (0×80 >> (n & 7)) of byte((char*)address + (n >> 3)) where n is the bit number and address is a pointer to the variable. This formula effectively breaks up the variable into 8-bit sized chunks and orders the bits in each chunk in reverse. For example, to test the lowest-order bit (bit 0) of a 32-bit integer, you would actually specify 7 for the bit number; similarly, to test the highest order bit (bit 32), you would specify 24 for the bit number. |
// Listing 4-2 Using a mutex lock
void MyMutexInitFunction()
{
pthread_mutex_init(&mutex, NULL);
}
void MyLockingFunction()
{
// Lock the mutex
pthread_mutex_lock(&mutex);
// Do real the work
// unlock the mutex
pthread_mutex_unlock(&mutex);
}
2,使用NSLock类
Cocoa中所有的锁的接口实际上都是通过NSLocking协议定义的,除了定义了lock/unlock方法外,还定义了tryLock/lockBeforeDate:方法。tryLock方法试图获取一个锁,如果所不可用,他不会阻塞线程,相反,他只返回NO。lockBeforeDate:方法试图获取一个锁,如果锁没有在规定的时间内被获取到,他会让线程,从阻塞状态变为非阻塞状态(或者返回NO)。
- (void)testUsingLock
{
BOOL moreToDo = NO;
NSLock *theLock = [[NSLock alloc] init];
while(moreToDo)
{
/* Do another increment of calculation */
/* until there's no more to do. */
if([theLock tryLock])
{
/* Update the display used by all threads */
[theLock unlock];
}
}
}
3,使用@synchronized指令
@synchronized指令做和其他互斥锁一样的工作(防止不同线程在同一时间获取同一个锁)
- (void)MyMethod:(id)anObj
{
@synchronized(anObj)
{
// Everything between the braces is protected by the @synchronized directive.
}
}
创建@synchronized(anObj)指令的对象是一个用来区别保护块的唯一标示符,如果在不同线程调用上述方法,如果每次在线程传递的不同的对象给anObj,那么每次他都将拥有他的锁,并持续处理,而不被其他线程阻塞。如果传递的是同一参数,那么该线程被阻塞,直到前一个线程解锁后,才能继续处理
另,@synchronized()块隐式的添加一个异常处理例程来保护代码,所以需要在程序中启用异常处理。
4,使用其他锁
1)使用NSRecursiveLock对象---递归锁
对同一线程,可以多次获得(lock)而不会造成死锁,注意的是lock/unlock需要配对出现
NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init];
- (void)MyRecursiveLockFunction:(int)value
{
[theLock lock];
if(value != 0)
{
-- value;
[self MyRecursiveLockFunction:value];
}
[theLock unlock];
}
2)使用NSConditionLock对象---条件锁
条件锁是一个互斥锁,可以通过特定值来锁住和解锁。
NSConditionLock的锁住和解锁的方法,unlockWithCondition:和lock消息,或者lockWhenCondition:和unlock消息。两对可以任意组合使用
===生产者-消费者问题
#define NO_DATA 0
#define HAS_DATA 1
isEmpty = NO;
NSConditionLock *condLock = [[NSConditionLock alloc] initWithCondition:NO_DATA];
// 生产者线程数据处理流程
- (void)MyConditionLockPruductor
{
while(true)
{
[condLock lock];
/* Add data to the queue */
[condLock unlockWithCondition:HAS_DATA];
}
}
// 消费者线程数据处理流程
- (void)MyConditionLockCustomer
{
while(true)
{
[condLock lockWhenCondition:HAS_DATA];
/* remove data from the queue */
[condLock unlockWithCondition:(isEmpty?NO_DATA:HAS_DATA)];
// Process the data locally.
}
}
3)使用NSDistributedLock对象---分布锁
用于协调多台主机访问某系共享资源,比如一个文件/一个目录等。和其他lock锁的不同,NSDistributedLock对象并没有实现NSLocking协议,所以他没有lock方法。不过提供了一个tryLock方法,可以通过breadLock方法打破现在锁。
// Listing 4-3 Using a Cocoa condition
- (void)testUsingConditoin
{
[cocaoCondition lock];
while(timeToDoWork <= 0)
{
[cocaoCondition wait];
}
-- timeToDoWork;
// Do real work here
[cocaoCondition unlock];
}
// Listing 4-4 Signaling a Cocoa condition
- (void)signalCocaoConditon
{
[cocaoCondition lock];
++ timeToDoWork;
[cocaoCondition signal];
[cocaoCondition unlock];
}
pthread_mutex_t mutex;
pthread_cond_t condition;
Boolean ready_to_go = true;
void MyCondInitFunction()
{
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&condition, NULL);
}
void MyWaitOnConditionFunction()
{
// Lock the mutex
pthread_mutex_lock(&mutex);
// if the predicate is already set, then the while loop is bypassed;
// otherwise, the thread sleeps until the predicate is set
while(ready_to_go == false)
{//这个while要特别说明一下,单个pthread_cond_wait功能很完善,为何这里要有一个while (head == NULL)呢?因为pthread_cond_wait里的线程可能会被意外唤醒,如果这个时候head != NULL,则不是我们想要的情况。这个时候,应该让线程继续进入pthread_cond_wait
pthread_cond_wait(&condition, &mutex);// pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的mutex,然后阻塞在等待对列里休眠,直到再次被唤醒(大多数情况下是等待的条件成立而被唤醒,唤醒后,该进程会先锁定先pthread_mutex_lock(&mutex);,再读取资源
//用这个流程是比较清楚的 /*block-->unlock-->wait() return-->lock*/
}
// Do work. (The mutex should stay locked.)
// Reset the predicate and release the mutex.
ready_to_go = false;
pthread_mutex_unlock(&mutex);
}
===使用POSIX条件,通知解锁
// Listing 4-6 Signaling a condition lock
void signalThreadUsingCondition()
{
// At the point, there should be work for the other thread to do
pthread_mutex_lock(&mutex);
ready_to_go = true;
// signal the other thread to begin work
pthread_cond_signal(&condition);
pthread_mutex_unlock(&mutex);
}
术语表
应用(application) 一个显示一个图形用户界面给用户的特定样式程序。
条件(condition) 一个用来同步资源访问的结构。线程等待某一条件来决定是否被允许继续运行,直到其他线程显式的给该条件发送信号。
临界区(critical section) 同一时间只能不被一个线程执行的代码。
输入源(input source) 一个线程的异步事件源。输入源可以是基于端口的或手工触发,并且必须被附加到某一个线程的 run loop 上面。
可连接的线程(join thread) 退出时资源不会被立即回收的线程。可连接的线程在资源被回收之前必须被显式脱离或由其他线程连接。可连接线程
Arodung: 关于预览相册,放大后可控性太差怎么解决?
youran1024: @property (nonatomic, readonly, copy) NSArray *sub...
wzzvictory_tjsd: MRC下__block修饰的对象变量在block里不会被retain,但ARC下会
llccllccllcc: 简单易用!通俗易懂!博主深得苹果公司产品设计的理念啊!
qq_25558095: 谢谢
u010917803: 然并卵
skyashsz: 写的不错,正在从Android转IOS,有很大的参考价值
Shannon_Chang: j j ji
u010670117: 写的感觉好乱。。。。。
sinat_31954205: 谢谢楼主