2017-10-11 2 views
2

Ce code indique-t-il que CFAttributedString n'est pas thread-safe? Ou est-ce que je fais quelque chose de mal dans la configuration?Sécurité de thread CFAttributedString

Je pensais que CFAttributedString était sûr de lire à partir de plusieurs threads, mais je vois des plantages dans ce code à quelques reprises.

@IBAction func testIt(_ sender: Any?) { 
    let testString = "Hello world! Lets make this a bit longerrrrrrrrrrrrrrrr." as CFString 
    let testStringLength = CFStringGetLength(testString) 

    let testAttributedString = CFAttributedStringCreateMutable(kCFAllocatorDefault, testStringLength) 
    CFAttributedStringReplaceString(testAttributedString, CFRange(location: 0, length: 0), testString) 
    CFAttributedStringEndEditing(testAttributedString) 
    for i in 0..<testStringLength { 
     let range = CFRange(location: i, length: 1) 
     let keyAndValue = "\(i)" as CFString 
     CFAttributedStringSetAttribute(testAttributedString, range, keyAndValue, keyAndValue) 
    } 

    let immutableTestAttributedString = CFAttributedStringCreateCopy(kCFAllocatorDefault, testAttributedString) 
    DispatchQueue.concurrentPerform(iterations: 100) { _ in 
     var index: CFIndex = 0 
     var effectiveRange: CFRange = CFRange(location: 0, length: 0) 
     while index < testStringLength { 
      // Crash happens here EXC_BAD_ACCESS (code=1, address=0x24) 
      let _ = CFAttributedStringGetAttributes(immutableTestAttributedString, index, &effectiveRange) 
      index = effectiveRange.location + effectiveRange.length 
     } 
    } 
} 

Répondre

1
let testString = "Hello world! Lets make this a bit longerrrrrrrrrrrrrrrr." as CFString 

Ceci est une chaîne Swift se faisant passer pour un CFString, qui est environ deux couches de indirection et invoque un chemin de code très différent dans les tripes (si cela devrait fonctionner ou non entre vous et un radar). Essayez de créer un bon CFString et de voir si cela fonctionne comme vous l'attendez.

var bytes = Array("Hello world! Lets make this a bit longerrrrrrrrrrrrrrrr.".utf16) 
let testString = CFStringCreateWithCharacters(nil, &bytes, bytes.count) 

(Bien sûr, je vous recommande fortement de faire tout ce travail dans NSAttributedString plutôt que CFAttributedString. Le Swift-> Fondation pont est beaucoup plus simple et est utilisé en permanence par rapport à la Swift-> Foundation-> CoreFoundation pont. Cela peut juste un bogue dans ce pont, mais votre monde est toujours va être beaucoup plus facile si vous l'éviter.)


Bien que je ne l'ai pas été en mesure de reproduire le problème w/a CFString pur, ce n'est définitivement pas sécurisé. CoreFoundation est open source (sorte de ..., mais assez pour cela), vous pouvez donc regarder le code vous-même. Finalement, CFAttributedStringGetAttributes appelle blockForLocation, ce qui met à jour un cache interne et ne le verrouille pas. Je n'ai rien vu dans les docs qui promet que c'est thread safe.

+0

Merci pour le conseil, malheureusement, je vois toujours une erreur au même endroit lorsque je crée la chaîne de cette façon. La raison de l'utilisation de CFAttributedString dans ce cas est parce que c'est un endroit chaud dans le code et CFAttributedStringSetAttribute semble courir beaucoup plus vite que d'ajouter des attributs avec NSMutableAttributedString. –

+0

Avez-vous des indications pour savoir comment fonctionne le pontage rapide? Et surtout les problèmes de performance à surveiller. Je travaille beaucoup avec Core Text de Swift et je suis maintenant en phase d'optimisation. Merci. –

+0

Merci, pour votre aide. Je m'attendais à un thread sûr puisque NSAttributedString est répertorié comme sûr et Core Foundation a été annoncé comme "généralement" sûr ici: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html Mais dans ce cas PAS, très bon à savoir et merci encore pour votre aide. –