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

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

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

Ответы [ 7 ]

4 голосов
/ 16 сентября 2008

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

Там нет бесплатного обеда.

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

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

1 голос
/ 16 сентября 2008

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

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

0 голосов
/ 16 сентября 2008

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

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

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

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

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

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

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

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

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

0 голосов
/ 16 сентября 2008

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

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

0 голосов
/ 16 сентября 2008

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

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

0 голосов
/ 16 сентября 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...