Slide 1

Slide 1 text

DispatchQueue.sync が動作するスレッド

Slide 2

Slide 2 text

自己紹介 Twitter: Iceman (@iceman5499) Github:okamura (sidepelican) クックパッド株式会社 名前とアイコンとIDがブレブレ太郎なので最近はIcemanで統一しよ うと考えてます

Slide 3

Slide 3 text

DispatchQueueでありがちなデッドロック 軽い気持ちで呼んだ関数が内部で DispatchQueue.sync を使っていた

Slide 4

Slide 4 text

便利関数が用意される

Slide 5

Slide 5 text

これでクラッシュしない! めでたしめでたし

Slide 6

Slide 6 text

しかしここで疑問が 次のようなコードを実行するとき

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

しかしここで疑問が 実際に実行するとクラッシュしない この場合 Thread.isMainThread は true を返す myqueue の中から呼んでいるのに、なぜ? (この時点で僕は勘違いをしています)

Slide 9

Slide 9 text

apple/swift‑corelibs‑libdispatch

Slide 10

Slide 10 text

デッドロックを発生させてエラーからソースをたどる dispatch_sync called on queue already owned by current thread というエラー文をswift‑corelibs‑libdispatchから grep → 出ない

Slide 11

Slide 11 text

あった( _dispatch_sync_wait ) C++の文字列リテラルは空白や改行があれば結合されるので、そこ で分かれていた

Slide 12

Slide 12 text

デッドロック判定処理をたどる _dq_state_drain_locked_by が判定しているっぽい typedef uint32_t dispatch_tid; typedef uint32_t dispatch_lock;

Slide 13

Slide 13 text

#define DLOCK_OWNER_MASK ((dispatch_lock)0xfffffffc) C にありがちなビット演算 dq_state と tid の下位3~32bitが同一かどうかで比較されてる dq_state は DispatchQueue が管理している値っぽいので、 tid が何か分かれば良さそう

Slide 14

Slide 14 text

_dispatch_sync_waitに戻る tid は _dispatch_tid_self() から来てるっぽい

Slide 15

Slide 15 text

#define _dispatch_tid_self() \ ((dispatch_tid)_dispatch_thread_port()) #define _dispatch_thread_port() \ pthread_mach_thread_np(_dispatch_thread_self()) ようやく見慣れた関数が出てくる ( pthread_self ) OSによって分岐しているが、実態はpthreadのスレッドID(あるい は同等にみなせる代物)っぽい

Slide 16

Slide 16 text

_dispatch_sync_waitに戻る sync処理を行う対象のスレッドが現在のスレッドならデッドロック と判定しクラッシュさせている

Slide 17

Slide 17 text

最初の疑問に戻り、なぜrunOnMainThreadは問題なさ そうなのか

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

そもそもの勘違い DispatchQueue はそれぞれが専用のスレッドを持っていてその中 でのみ動作するものだと思いこんでいた これだとconcurrent queueは何者やねん!ってなる

Slide 20

Slide 20 text

最後に 事の発端となった DispatchQueue.main.sync だが、そもそもこ れをしなきゃいけない場面はほぼないはず 適切に DispatchQueue (や、Lock)を使っていこう