То, что вы читаете, не означает, что вы думаете, что это значит. Прежде всего, попробуйте страницу msdn для самой shared_ptr .
Прокрутите вниз в раздел «Замечания», и вы попадете в мясо проблемы. В принципе, shared_ptr<>
указывает на «блок управления», который отслеживает, сколько объектов shared_ptr<>
фактически указывают на объект «Real». Поэтому, когда вы это делаете:
shared_ptr ptr1 = make_shared();
Пока есть только один вызов для выделения памяти здесь через make_shared
, есть два «логических» блока, которые вы не должны относиться к ним одинаково. Одним из них является int
, в котором хранится фактическое значение, а другое - блок управления, в котором хранится все shared_ptr<>
«магия», которая заставляет его работать.
Это только сам блок управления, является потокобезопасным.
Я положил это на свою линию для акцента. Содержимое shared_ptr
не является потокобезопасным и не записывается в тот же экземпляр shared_ptr
. Вот что продемонстрировать, что я имею в виду:
// In main()
shared_ptr global_instance = make_shared();
// (launch all other threads AFTER global_instance is fully constructed)
//In thread 1
shared_ptr local_instance = global_instance;
Это прекрасно, на самом деле вы можете делать это во всех потоках столько, сколько хотите. И тогда, когда local_instance
разрушается (выходить из области видимости), он также является потокобезопасным. Кто-то может получить доступ к global_instance
, и это не изменит ситуацию. Фрагмент, который вы вытащили из msdn, в основном означает, что «доступ к блоку управления является потокобезопасным», поэтому другие экземпляры shared_ptr<>
могут быть созданы и уничтожены на разных потоках столько, сколько необходимо.
//In thread 1
local_instance = make_shared();
Это хорошо. Он будет воздействовать на объект global_instance
, но только косвенно. Контрольный блок, на который он указывает, будет уменьшаться, но делается поточно-безопасным способом. local_instance
больше не будет указывать на тот же объект (или контрольный блок), как это делает global_instance
.
//In thread 2
global_instance = make_shared();
Это почти наверняка не очень хорошо, если global_instance
доступен из любых других потоков (что вы говорите, что делаете). Для этого нужна блокировка, если вы делаете это, потому что пишете там, где живет global_instance
, а не только чтение от него. Поэтому запись в объект из нескольких потоков является плохим, если только вы не охраняете его через блокировку. Таким образом, вы можете читать из global_instance
объекта, назначая из него новые shared_ptr<>
объекты, но вы не можете его записать.
// In thread 3
*global_instance = 3;
int a = *global_instance;
// In thread 4
*global_instance = 7;
Значение a
не определено. Это может быть 7, или может быть 3, или это может быть что-то еще. Безопасность потоков экземпляров shared_ptr<>
применяется только к управлению экземплярами shared_ptr<>
, которые были инициализированы друг от друга, а не тем, на что они указывают.
Чтобы подчеркнуть, что я имею в виду, посмотрите на это:
shared_ptr global_instance = make_shared(0);
void thread_fcn();
int main(int argc, char** argv)
{
thread thread1(thread_fcn);
thread thread2(thread_fcn);
...
thread thread10(thread_fcn);
chrono::milliseconds duration(10000);
this_thread::sleep_for(duration);
return;
}
void thread_fcn()
{
// This is thread-safe and will work fine, though it's useless. Many
// short-lived pointers will be created and destroyed.
for(int i = 0; i < 10000; i++)
{
shared_ptr temp = global_instance;
}
// This is not thread-safe. While all the threads are the same, the
// "final" value of this is almost certainly NOT going to be
// number_of_threads*10000 = 100,000. It'll be something else.
for(int i = 0; i < 10000; i++)
{
*global_instance = *global_instance + 1;
}
}
A shared_ptr<>
- механизм, гарантирующий, что владельцы нескольких объектов гарантируют разрушение объекта, а не механизм для обеспечения нескольких потоков может получить доступ к объекту правильно. Вам еще нужен отдельный механизм синхронизации для безопасного использования в нескольких потоках (например, std :: mutex ).
Лучший способ подумать об этом IMO - это то, что shared_ptr<>
делает что несколько копий, указывающих на одну и ту же память, не имеют проблем с синхронизацией самого , но ничего не делают для объекта, на который указывает. Относитесь к этому так.
drawLayer: inContext:
не будет вызываться, если ваш кадр CGRectZero или вне экрана. Кроме того, если ваш CALayer не прикреплен к существующему экранному слою, он никогда не будет рисоваться, независимо от того, сколько раз вы вызываете setNeedsDisplay