mirror of
https://github.com/HackPlan/AsyncDisplayKit.git
synced 2026-04-29 20:26:00 +08:00
[ASThread] Add SharedLocker and SharedUnlocker that uses a shared pointer for the mutex (#2047)
* Add SharedLocker and SharedUnlocker that uses a shared pointer for the mutex * Move ASTextKitContext to use Shared Locker
This commit is contained in:
committed by
Adlai Holler
parent
d9db780b0b
commit
aba05a747c
@@ -34,6 +34,8 @@ static inline BOOL ASDisplayNodeThreadIsMain()
|
|||||||
#import <QuartzCore/QuartzCore.h>
|
#import <QuartzCore/QuartzCore.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
For use with ASDN::StaticMutex only.
|
For use with ASDN::StaticMutex only.
|
||||||
*/
|
*/
|
||||||
@@ -53,7 +55,7 @@ static inline BOOL ASDisplayNodeThreadIsMain()
|
|||||||
|
|
||||||
|
|
||||||
namespace ASDN {
|
namespace ASDN {
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
class Locker
|
class Locker
|
||||||
{
|
{
|
||||||
@@ -98,17 +100,72 @@ namespace ASDN {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class SharedLocker
|
||||||
|
{
|
||||||
|
std::shared_ptr<T> _l;
|
||||||
|
|
||||||
|
#if TIME_LOCKER
|
||||||
|
CFTimeInterval _ti;
|
||||||
|
const char *_name;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
#if !TIME_LOCKER
|
||||||
|
|
||||||
|
SharedLocker (std::shared_ptr<T> const& l) ASDISPLAYNODE_NOTHROW : _l (l) {
|
||||||
|
assert(_l != nullptr);
|
||||||
|
_l->lock ();
|
||||||
|
}
|
||||||
|
|
||||||
|
~SharedLocker () {
|
||||||
|
_l->unlock ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// non-copyable.
|
||||||
|
SharedLocker(const SharedLocker<T>&) = delete;
|
||||||
|
SharedLocker &operator=(const SharedLocker<T>&) = delete;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
SharedLocker (std::shared_ptr<T> const& l, const char *name = NULL) ASDISPLAYNODE_NOTHROW : _l (l), _name(name) {
|
||||||
|
_ti = CACurrentMediaTime();
|
||||||
|
_l->lock ();
|
||||||
|
}
|
||||||
|
|
||||||
|
~SharedLocker () {
|
||||||
|
_l->unlock ();
|
||||||
|
if (_name) {
|
||||||
|
printf(_name, NULL);
|
||||||
|
printf(" dt:%f\n", CACurrentMediaTime() - _ti);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
class Unlocker
|
class Unlocker
|
||||||
{
|
{
|
||||||
T &_l;
|
T &_l;
|
||||||
public:
|
public:
|
||||||
Unlocker (T &l) ASDISPLAYNODE_NOTHROW : _l (l) {_l.unlock ();}
|
Unlocker (T &l) ASDISPLAYNODE_NOTHROW : _l (l) { _l.unlock (); }
|
||||||
~Unlocker () {_l.lock ();}
|
~Unlocker () {_l.lock ();}
|
||||||
Unlocker(Unlocker<T>&) = delete;
|
Unlocker(Unlocker<T>&) = delete;
|
||||||
Unlocker &operator=(Unlocker<T>&) = delete;
|
Unlocker &operator=(Unlocker<T>&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class SharedUnlocker
|
||||||
|
{
|
||||||
|
std::shared_ptr<T> _l;
|
||||||
|
public:
|
||||||
|
SharedUnlocker (std::shared_ptr<T> const& l) ASDISPLAYNODE_NOTHROW : _l (l) { _l->unlock (); }
|
||||||
|
~SharedUnlocker () { _l->lock (); }
|
||||||
|
SharedUnlocker(SharedUnlocker<T>&) = delete;
|
||||||
|
SharedUnlocker &operator=(SharedUnlocker<T>&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
struct Mutex
|
struct Mutex
|
||||||
{
|
{
|
||||||
@@ -164,7 +221,9 @@ namespace ASDN {
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef Locker<Mutex> MutexLocker;
|
typedef Locker<Mutex> MutexLocker;
|
||||||
|
typedef SharedLocker<Mutex> MutexSharedLocker;
|
||||||
typedef Unlocker<Mutex> MutexUnlocker;
|
typedef Unlocker<Mutex> MutexUnlocker;
|
||||||
|
typedef SharedUnlocker<Mutex> MutexSharedUnlocker;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
If you are creating a static mutex, use StaticMutex and specify its default value as one of ASDISPLAYNODE_MUTEX_INITIALIZER
|
If you are creating a static mutex, use StaticMutex and specify its default value as one of ASDISPLAYNODE_MUTEX_INITIALIZER
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#import "ASLayout.h"
|
#import "ASLayout.h"
|
||||||
|
|
||||||
#import <queue>
|
#import <queue>
|
||||||
|
#import <memory>
|
||||||
|
|
||||||
#import "NSArray+Diffing.h"
|
#import "NSArray+Diffing.h"
|
||||||
#import "ASEqualityHelpers.h"
|
#import "ASEqualityHelpers.h"
|
||||||
@@ -47,7 +48,8 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@implementation ASLayoutTransition {
|
@implementation ASLayoutTransition {
|
||||||
ASDN::RecursiveMutex __instanceLock__;
|
std::shared_ptr<ASDN::RecursiveMutex> __instanceLock__;
|
||||||
|
|
||||||
BOOL _calculatedSubnodeOperations;
|
BOOL _calculatedSubnodeOperations;
|
||||||
NSArray<ASDisplayNode *> *_insertedSubnodes;
|
NSArray<ASDisplayNode *> *_insertedSubnodes;
|
||||||
NSArray<ASDisplayNode *> *_removedSubnodes;
|
NSArray<ASDisplayNode *> *_removedSubnodes;
|
||||||
@@ -61,6 +63,8 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
|||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
|
__instanceLock__ = std::make_shared<ASDN::RecursiveMutex>();
|
||||||
|
|
||||||
_node = node;
|
_node = node;
|
||||||
_pendingLayout = pendingLayout;
|
_pendingLayout = pendingLayout;
|
||||||
_previousLayout = previousLayout;
|
_previousLayout = previousLayout;
|
||||||
@@ -70,7 +74,7 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
|||||||
|
|
||||||
- (BOOL)isSynchronous
|
- (BOOL)isSynchronous
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
return !ASLayoutCanTransitionAsynchronous(_pendingLayout);
|
return !ASLayoutCanTransitionAsynchronous(_pendingLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +86,7 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
|||||||
|
|
||||||
- (void)applySubnodeInsertions
|
- (void)applySubnodeInsertions
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
[self calculateSubnodeOperationsIfNeeded];
|
[self calculateSubnodeOperationsIfNeeded];
|
||||||
|
|
||||||
NSUInteger i = 0;
|
NSUInteger i = 0;
|
||||||
@@ -95,7 +99,7 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
|||||||
|
|
||||||
- (void)applySubnodeRemovals
|
- (void)applySubnodeRemovals
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
[self calculateSubnodeOperationsIfNeeded];
|
[self calculateSubnodeOperationsIfNeeded];
|
||||||
for (ASDisplayNode *subnode in _removedSubnodes) {
|
for (ASDisplayNode *subnode in _removedSubnodes) {
|
||||||
[subnode removeFromSupernode];
|
[subnode removeFromSupernode];
|
||||||
@@ -104,7 +108,7 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
|||||||
|
|
||||||
- (void)calculateSubnodeOperationsIfNeeded
|
- (void)calculateSubnodeOperationsIfNeeded
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
if (_calculatedSubnodeOperations) {
|
if (_calculatedSubnodeOperations) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -134,27 +138,27 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
|||||||
|
|
||||||
- (NSArray<ASDisplayNode *> *)currentSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
- (NSArray<ASDisplayNode *> *)currentSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
return _node.subnodes;
|
return _node.subnodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray<ASDisplayNode *> *)insertedSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
- (NSArray<ASDisplayNode *> *)insertedSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
[self calculateSubnodeOperationsIfNeeded];
|
[self calculateSubnodeOperationsIfNeeded];
|
||||||
return _insertedSubnodes;
|
return _insertedSubnodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray<ASDisplayNode *> *)removedSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
- (NSArray<ASDisplayNode *> *)removedSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
[self calculateSubnodeOperationsIfNeeded];
|
[self calculateSubnodeOperationsIfNeeded];
|
||||||
return _removedSubnodes;
|
return _removedSubnodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (ASLayout *)transitionContext:(_ASTransitionContext *)context layoutForKey:(NSString *)key
|
- (ASLayout *)transitionContext:(_ASTransitionContext *)context layoutForKey:(NSString *)key
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
if ([key isEqualToString:ASTransitionContextFromLayoutKey]) {
|
if ([key isEqualToString:ASTransitionContextFromLayoutKey]) {
|
||||||
return _previousLayout;
|
return _previousLayout;
|
||||||
} else if ([key isEqualToString:ASTransitionContextToLayoutKey]) {
|
} else if ([key isEqualToString:ASTransitionContextToLayoutKey]) {
|
||||||
@@ -166,7 +170,7 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
|||||||
|
|
||||||
- (ASSizeRange)transitionContext:(_ASTransitionContext *)context constrainedSizeForKey:(NSString *)key
|
- (ASSizeRange)transitionContext:(_ASTransitionContext *)context constrainedSizeForKey:(NSString *)key
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
if ([key isEqualToString:ASTransitionContextFromLayoutKey]) {
|
if ([key isEqualToString:ASTransitionContextFromLayoutKey]) {
|
||||||
return _previousLayout.constrainedSizeRange;
|
return _previousLayout.constrainedSizeRange;
|
||||||
} else if ([key isEqualToString:ASTransitionContextToLayoutKey]) {
|
} else if ([key isEqualToString:ASTransitionContextToLayoutKey]) {
|
||||||
|
|||||||
@@ -10,13 +10,14 @@
|
|||||||
|
|
||||||
#import "ASTextKitContext.h"
|
#import "ASTextKitContext.h"
|
||||||
#import "ASLayoutManager.h"
|
#import "ASLayoutManager.h"
|
||||||
|
#import "ASThread.h"
|
||||||
|
|
||||||
#import <mutex>
|
#include <memory>
|
||||||
|
|
||||||
@implementation ASTextKitContext
|
@implementation ASTextKitContext
|
||||||
{
|
{
|
||||||
// All TextKit operations (even non-mutative ones) must be executed serially.
|
// All TextKit operations (even non-mutative ones) must be executed serially.
|
||||||
std::mutex _textKitMutex;
|
std::shared_ptr<ASDN::Mutex> __instanceLock__;
|
||||||
|
|
||||||
NSLayoutManager *_layoutManager;
|
NSLayoutManager *_layoutManager;
|
||||||
NSTextStorage *_textStorage;
|
NSTextStorage *_textStorage;
|
||||||
@@ -35,8 +36,11 @@
|
|||||||
{
|
{
|
||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
// Concurrently initialising TextKit components crashes (rdar://18448377) so we use a global lock.
|
// Concurrently initialising TextKit components crashes (rdar://18448377) so we use a global lock.
|
||||||
static std::mutex __static_mutex;
|
static ASDN::Mutex __staticMutex;
|
||||||
std::lock_guard<std::mutex> l(__static_mutex);
|
ASDN::MutexLocker l(__staticMutex);
|
||||||
|
|
||||||
|
__instanceLock__ = std::make_shared<ASDN::Mutex>();
|
||||||
|
|
||||||
// Create the TextKit component stack with our default configuration.
|
// Create the TextKit component stack with our default configuration.
|
||||||
if (textStorageCreationBlock) {
|
if (textStorageCreationBlock) {
|
||||||
_textStorage = textStorageCreationBlock(attributedString);
|
_textStorage = textStorageCreationBlock(attributedString);
|
||||||
@@ -60,13 +64,13 @@
|
|||||||
|
|
||||||
- (CGSize)constrainedSize
|
- (CGSize)constrainedSize
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> l(_textKitMutex);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
return _textContainer.size;
|
return _textContainer.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setConstrainedSize:(CGSize)constrainedSize
|
- (void)setConstrainedSize:(CGSize)constrainedSize
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> l(_textKitMutex);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
_textContainer.size = constrainedSize;
|
_textContainer.size = constrainedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +78,7 @@
|
|||||||
NSTextStorage *,
|
NSTextStorage *,
|
||||||
NSTextContainer *))block
|
NSTextContainer *))block
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> l(_textKitMutex);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
if (block) {
|
if (block) {
|
||||||
block(_layoutManager, _textStorage, _textContainer);
|
block(_layoutManager, _textStorage, _textContainer);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user