Est-il prudent de manipuler des objets que j'ai créés en dehors de mon thread si je n'y accède pas explicitement sur le thread qui les a créés?

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

Question

Je travaille sur un logiciel de cacao et, pour que l'interface graphique reste active pendant une importation massive de données (Core Data), je dois exécuter l'importation en dehors du thread principal.

Est-il prudent d’accéder à ces objets même si je les ai créés dans le thread principal sans utiliser de verrous si je n’accède pas explicitement à ces objets pendant l’exécution du thread.

Était-ce utile?

La solution

Avec Core Data, vous devez avoir un contexte d'objet géré distinct à utiliser pour votre thread d'importation, connecté au même coordinateur et au même magasin persistant. Vous ne pouvez pas simplement jeter les objets créés dans un contexte utilisé par le thread principal dans un autre thread et s'attendre à ce qu'ils fonctionnent. De plus, vous ne pouvez pas faire votre propre verrouillage pour cela; vous devez au moins verrouiller le contexte de l'objet géré dans lequel se trouvent les objets, selon le cas. Mais si ces vues sont liées à vos contrôles par des vues, il n'y a pas de "crochets". que vous pouvez ajouter ce verrouillage du contexte.

Il n'y a pas de repas gratuit.

Ben Trumbull explique certaines des raisons pour lesquelles vous devez utiliser un contexte distinct, et pourquoi "il vous suffit de lire" et n'est pas aussi simple ni aussi sûr que vous ne le pensez, dans cet excellent article de la fin de 2004 sur la liste webobjects-dev . (Le fil entier est génial.) Il discute de la structure Enterprise Objects et de WebObjects, mais ses conseils sont également applicables aux données de base. Il suffit de remplacer " EC " avec " NSManagedObjectContext " et " EOF " avec " Données de base " dans la viande de son message.

La solution au problème du partage de données entre les threads dans Core Data, comme le faisait auparavant le cadre Enterprise Objects Framework, était "non". Si vous y réfléchissez plus longuement et que vous devez vraiment, honnêtement, partager des données entre des threads, la solution consiste à conserver des graphiques d'objet indépendants dans des contextes isolés de thread et à utiliser les informations de la notification de sauvegarde d'un contexte pour indiquer au autre contexte ce qu'il faut récupérer. - [NSManagedObjectContext refreshObject: mergeChanges:] est spécifiquement conçu pour prendre en charge cette utilisation.

Autres conseils

Je pense que ce n'est pas sûr de le faire avec NSManagedObjects (ou sous-classes) gérées par un CoreData NSManagedObjectContext. En règle générale, CoreData peut résoudre de nombreux problèmes avec l'état des objets gérés, notamment les erreurs de déclenchement liées à ces objets dans des threads distincts. En particulier, [NSManagedObject initWithEntity: insertIntoManagedObjectContext:] (l'initialiseur désigné pour NSManagedObjects à partir de OS X 10.5) ne garantit pas que l'objet renvoyé peut être transmis en toute sécurité à un autre thread.

L'utilisation de CoreData avec plusieurs threads est bien documentée dans le dev site .

L'intérêt d'utiliser des verrous est de s'assurer que deux threads n'essayent pas d'accéder à la même ressource. Si vous pouvez garantir cela par un autre mécanisme, allez-y.

Même si c'est sûr, ce n'est pas la meilleure pratique d'utiliser des données partagées entre les threads sans synchroniser l'accès à ces champs. Peu importe quel thread a créé l'objet, mais si plus d'une ligne d'exécution (thread / processus) accède à l'objet en même temps, car cela peut entraîner une incohérence dans les données.

Si vous êtes absolument certain qu'un seul thread accédera jamais à cet objet, il serait prudent de ne pas synchroniser l'accès. Même dans ce cas, je préférerais mettre la synchronisation dans mon code maintenant plutôt que d’attendre à plus tard, quand un changement dans l’application mettrait un deuxième thread partageant les mêmes données sans se soucier de la synchronisation des accès.

Oui, c'est sûr. Un modèle assez courant consiste à créer un objet, puis à l'ajouter à une file d'attente ou à une autre collection. Un deuxième " consommateur " thread prend les éléments de la file d'attente et fait quelque chose avec eux. Ici, vous devez synchroniser la file d'attente, mais pas les objets ajoutés à celle-ci.

Ce n’est pas une bonne idée de tout synchroniser et d’espérer le meilleur. Vous devrez réfléchir très attentivement à votre conception et déterminer exactement quels threads peuvent agir sur vos objets.

Deux choses à considérer sont:

  • Vous devez être en mesure de garantir que l'objet est entièrement créé et initialisé avant de le rendre disponible pour d'autres threads.
  • Il doit exister un mécanisme permettant au thread principal (GUI) de détecter que les données ont été chargées et que tout va bien. Pour être en sécurité, cela impliquera inévitablement un verrouillage.

Oui, vous pouvez le faire, ce sera sûr

... jusqu'à ce que le second programmeur se présente et ne comprenne pas les mêmes hypothèses que vous avez faites. Ce second (ou 3ème, 4ème, 5ème, ...) programmeur est susceptible de commencer à utiliser l’objet d’une manière non sécurisée (dans le fil du créateur). Les problèmes causés pourraient être très subtils et difficiles à dépister. Pour cette seule raison, et parce que c'est tellement tentant d'utiliser cet objet dans plusieurs threads, je voudrais sécuriser le thread d'objet.

Pour clarifier, (merci à ceux qui ont laissé des commentaires):

Par "thread safe" Je veux dire par programme concevoir un schéma pour éviter les problèmes de threading. Je ne veux pas nécessairement concevoir un schéma de verrouillage autour de votre objet. Vous pourriez trouver dans votre langue un moyen de rendre illégal (ou très difficile) l'utilisation de l'objet dans le fil du créateur. Par exemple, limiter la portée, dans le fil du créateur, au bloc de code qui crée l'objet. Une fois créé, transmettez l'objet au thread utilisateur, en vous assurant que le thread créateur n'a plus de référence.

Par exemple, en C ++

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

Ensuite, dans votre thread de création, vous n’avez plus accès à l’objet après sa création, la responsabilité est transférée au thread qui utilise.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top