チーム全体、毎週金曜日の朝、一人3分 LT をやっています。忘れないように、また日本語の勉強もしたいと思います、記事として記録します。
最近はプロジェクトの改善をしています、テストコードの補足とスレッド管理の増強に注目しています。スレッド問題は発生する時、そもそもタイミングに敏感ですが、再現しにくい、デバッグも難しい、本当に忘れられない体験になると思います。。。WWDC 2016(Session 412) で公開されました機能ーーThread Sanitizer を使い始めましょう。この機能は Xcode に統合されています、略称は TSan です。
TSan を有効にすると:
Use of uninitialized mutexes
Thread leaks (missing pthred_join)
Unsafe calls in signal handlers (ex:malloc)
Unlock from wrong thread
Data races
以上の問題を全て発見できます。一番発生しやすい **Data races(データ競合)**を展開したい、データ競合の発生原因は同期ではない場合、複数のスレッドから同じメモリをアクセスする時、少なくとも一つのアクセスで write 操作を行っています。実際の運用中、表現としては:データの不整合、アプリのクラッシュなど。
最近改善中のアプリを例に:
[context performBlock:^{
if (result && context) {
result = [self persistentSaveContext:context]; // 1
}
}];
return result; // 2
result
は 1 と 2 二箇所で競合してしまう。1 で write
操作を行いながら、別スレッドの 2 はすでに戻す可能性があるので、データ不整合になるかもしれません。
修正方法はいくつかあります、非同期から同期に変更するとか、write 操作の実行タイミングを変更するとか。ここで、非同期メソッドの performBlock
を使わずに、同じ用途の同期メソッド performBlockAndWait
を使いました。そうすると、データ競合が解決されました。
[context performBlockAndWait:^{
if (result && context) {
result = [self persistentSaveContext:context]; // 1
}
}];
return result; // 2
実に Thread Sanitizer 機能はコンパイラ (Clang) レベルで統合されます、そのため、もし Swift でサーバーサイドを書くときにもコマンドラインで Thread Sanitizer を使えます:

現在、64bit シミュレーターまたは macOS 自体のみ Thread Sanitizer をサポートできますが、かなり素晴らしい機能だと思います。