Безопасно ли манипулировать объектами, которые я создал вне моего потока, если я не обращаюсь к ним явно в потоке, который их создал?

StackOverflow https://stackoverflow.com/questions/67154

Вопрос

Я работаю над программным обеспечением какао, и чтобы графический интерфейс оставался отзывчивым во время массового импорта данных (основные данные), мне нужно запустить импорт вне основного потока.

Безопасно ли получать доступ к этим объектам, даже если я создал их в основном потоке без использования блокировок? если Я не обращаюсь к этим объектам явным образом во время работы потока.

Это было полезно?

Решение

При использовании Core Data у вас должен быть отдельный контекст управляемого объекта, который можно использовать для потока импорта, подключенный к тому же координатору и постоянному хранилищу.Вы не можете просто перебрасывать объекты, созданные в контексте, используемом основным потоком, в другой поток и ожидать, что они будут работать.Более того, вы не можете сделать для этого собственную блокировку;вы должны как минимум заблокировать контекст управляемого объекта, в котором находятся объекты, в зависимости от ситуации.Но если эти объекты привязаны к вашим представлениям и элементам управления, не существует «крючков», к которым вы могли бы добавить эту блокировку контекста.

Бесплатного обеда не бывает.

Бен Трамбалл объясняет некоторые причины, по которым вам необходимо использовать отдельный контекст и почему «просто читать» не так просто и безопасно, как вы думаете. этот замечательный пост конца 2004 года в списке webobjects-dev.(Вся тема великолепна.) Он обсуждает Enterprise Objects Framework и WebObjects, но его советы полностью применимы и к Core Data.Просто замените «EC» на «NSManagedObjectContext» и «EOF» на «Core Data» в тексте его сообщения.

Решение проблемы обмена данными между потоками в основных данных, таких как структура объектов Enterprise до этого, является «не так». Если вы думали об этом дальше, и вам действительно, честно говоря, нужно делиться данными между потоками, то решение состоит в том, чтобы сохранить независимые графики объектов в условиях, изолированных потоком, и использовать информацию в уведомлении сохранения из одного контекста, чтобы рассказать Другой контекст, что переназначить. -[NSManagedObjectContext refreshObject:mergeChanges:] специально разработан для поддержки такого использования.

Другие советы

Я верю, что это нет безопасно делать с NSManagedObjects (или подклассами), которые управляются CoreData NSManagedObjectContext.В общем, CoreData может выполнять множество сложных действий с состоянием управляемых объектов, включая выдачу ошибок, связанных с этими объектами, в отдельных потоках.В частности, [NSManagedObject initWithEntity:insertIntoManagedObjectContext:] (назначенный инициализатор для NSManagedObjects в OS X 10.5) не гарантирует, что возвращаемый объект можно безопасно передать в другой поток.

Использование CoreData с несколькими потоками хорошо документировано на сайте Apple. сайт разработчиков.

Весь смысл использования блокировок заключается в том, чтобы гарантировать, что два потока не попытаются получить доступ к одному и тому же ресурсу.Если вы можете гарантировать это с помощью какого-то другого механизма, сделайте это.

Даже если это безопасно, использовать общие данные между потоками без синхронизации доступа к этим полям — не лучшая практика.Не имеет значения, какой поток создал объект, но если к объекту одновременно обращается более одной строки выполнения (потока/процесса), поскольку это может привести к несогласованности данных.

Если вы абсолютно уверены, что только один поток когда-либо получит доступ к этому объекту, то было бы безопасно не синхронизировать доступ.Даже в этом случае я лучше внесу синхронизацию в свой код сейчас, чем буду ждать, пока изменение в приложении приведет к тому, что второй поток будет использовать те же данные, не беспокоясь о синхронизации доступа.

Да, это безопасно.Довольно распространенный шаблон — создать объект, а затем добавить его в очередь или другую коллекцию.Второй «потребительский» поток берет элементы из очереди и что-то с ними делает.Здесь вам потребуется синхронизировать очередь, а не объекты, добавляемые в очередь.

НЕ хорошая идея просто синхронизировать все и надеяться на лучшее.Вам нужно будет очень тщательно продумать свой дизайн и то, какие именно потоки могут воздействовать на ваши объекты.

Две вещи, которые следует учитывать:

  • Вы должны быть в состоянии гарантировать, что объект полностью создан и инициализирован, прежде чем он станет доступен другим потокам.
  • Должен быть какой-то механизм, с помощью которого основной поток (GUI) обнаруживает, что данные загружены и все в порядке.Чтобы обеспечить потокобезопасность, это неизбежно потребует какой-либо блокировки.

Да, вы можете это сделать, это будет безопасно

...пока второй программист не придет и не поймет те же предположения, которые вы сделали.Этот второй (или третий, четвертый, пятый...) программист, скорее всего, начнет использовать объект небезопасным способом (в потоке создателя).Вызванные проблемы могут быть очень тонкими, и их трудно отследить.Только по этой причине, а также потому, что очень заманчиво использовать этот объект в нескольких потоках, я бы сделал объект безопасным для потоков.

Чтобы внести ясность (спасибо тем, кто оставил комментарии):

Под «потокобезопасностью» я подразумеваю программную разработку схемы, позволяющей избежать проблем с многопоточностью.Я не обязательно имею в виду разработку схемы блокировки вокруг вашего объекта.Вы можете найти способ на своем языке сделать незаконным (или очень трудным) использование объекта в потоке создателя.Например, ограничение области действия в потоке создателя блоком кода, создающим объект.После создания передайте объект пользовательскому потоку, убедившись, что поток создателя больше не имеет ссылки на него.

Например, в С++

void CreateObject()
{
    Object* sharedObj = new Object();
    PassObjectToUsingThread( sharedObj); // this function would be system dependent
}

Тогда в вашем потоке создания у вас больше нет доступа к объекту после его создания, ответственность передается потоку использования.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top