Linuxドライバ_LDD3メモ_並行処理と競争状態

並行処理と競争状態                                (※マルチコア対応関連
1)発生原因                            
    SMPシステムでは、異なるプロセッサ上でコードを同時に実行することができます。                        
    カーネルコードはプリエンプティブであり、ドライバコードはいつでもプロセッサを手放します。                        
    ・複数のプロセスが同一ドライバを呼ばれた場合                        
    ・割り込みハンドラ                        
    ・非同期のカーネルイベントへの応答                        
    など                        
    (性質上、ハードウェアリソースは共有されるものであり、しばしばソフトウェアリソースも複数のスレッドから利用する必要があります。)                        

2)対策            
    アクセス管理の一般的なテクニックは、「ロッキング」または「相互排他」と呼ばれます。        
    ロック性能測定は、【lockmeter】というツールを使えば、カーネルはロックでの待ち時間を測定できる。        
    ①セマフォとミューテックス        
        ・関連構造体: struct semaphore    
        ・関連関数    
            void sema_init(struct semaphore *sem, int val);

            DECLARE_MUTEX(name);
            DECLARE_MUTEX_LOCKED(name);

            void init_MUTEX(struct semaphore *sem);
            void init_MUTEX_LOCKED(struct semaphore *sem);

            void down(struct semaphore *sem);
            int down_interruptible(struct semaphore *sem);
            int down_trylock(struct semaphore *sem);

            void up(struct semaphore *sem);
    ②Reader/Writerのセマフォ        
        ・関連構造体: struct rw_semaphore    
        ・関連関数    
            void init_rwsem(struct rw_semaphore *sem);

            void down_read(struct rw_semaphore *sem);
            int down_read_trylock(struct rw_semaphore *sem);
            void up_read(struct rw_semaphore *sem);

            void down_write(struct rw_semaphore *sem);
            int down_write_trylock(struct rw_semaphore *sem);
            void up_write(struct rw_semaphore *sem);
            void downgrade_write(struct rw_semaphore *sem);                                                                    
    ③Completion                                                                            
        Completionは、あるタスクが別のタスクに、ジョブが完了したことを通知する。                                                                        
        ・関連構造体: struct completion                                                                         
        ・関連関数                                                                        
            DECLARE_COMPLETION(my_completion);                                                                     
            init_completion(&my_completion);                                                                      
            INIT_COMPLETION(struct completion c);                                                                     

            void wait_for_completion(struct completion *c);                                                                     

            void complete(struct completion *c);                                                                    
            void complete_all(struct completion *c);       // completionはひとつのスレッドへ、completion_allはすべてのスレッドへ。
            void complete_and_exit(struct completion *c, long retval);     // Completionを待つ。
    ④スピンロック                                                                            
        セマフォと異なり、スピンロックは、割り込みハンドラのようなスリップできないコードで使われる。                                                                        
        性能がセマフォより高い。    
        ロック済、未ロックといった2種類状態しかない。    
        ・関連構造体:     
        ・関連関数    
            spinlock_t my_lock = SPIN_LOCK_UNLOCKED;
            void spin_lock_init(spinlock_t *lock);

            void spin_lock(spinlock_t *lock);
            void spin_unlock(spinlock_t *lock);

            void read_lock(rwlock_t *lock);
            void read_unlock(rwlock_t *lock);

            void write_lock(rwlock_t *lock);
            void write_unlock(rwlock_t *lock);
            など。
        ・スピンロックの原則    
            スピンロックを保持している間は、
            一、どのコードもアトミックでないといけない。
            二、割り込みを無効にする必要がある。
            三、できるだけ最小限の時間に限る。
★    ⑤ロックに代わる方法        
        マルチコアの場合、ロックが適当な対策でない場合がある。    
        代わりにアトミックなアクセスや、アルゴリズムで対策する。    
        ・環状バッファ  (特にネットワークアダプタでは、環状バッファを使うのが一般的です。<inux/kfifo.h>)    
        ・整数操作アトミック (atomic_t。一部プロセッサ制限のため、24ビットを超える分は使えない。 <asm/atomic.h>)    
            void atomic_set(atomic_t *v, int i);
            int atomic_read(atomic_t *v);
            void atomic_add(int i, atomic_t *v);
            void atomic_inc(atomic_t *v);
            void atomic_dec(atomic_t *v);
            など。
        ・ビット操作アトミック (アーキテクチャ依存。<asm/bitops.h>        
            void set_bit(nr, void *addr);    
            void clear_bit(nr, void *addr);    
            void change_bit(nr, void *addr);    
            など。    
        ・seqlock  (<linux/seqlock.h>)        
            Linux2.6からは、速く、ロックなしで共有リソースにアクセスできる新しい仕組みseqlockが組み込まれました。    
            seqlockは保護するリソースが小さく、単純で、頻繁にアクセスされて、書き込みは稀だが速さが要求される場合に使用します。    
            seqlockは、ポインタを含むデータ構造体を保護するためには使えません。    
            データ型: seqlock_t    
            関連関数:    
                unsigned int read_seqbegin_irqsave(seqlock_t *lock, unsigned long flags);
                int read_seqretry_irqrestore(seqlock_t *lock, unsigned int seq, unsigned long flags);
                void write_seqlock(seqlock_t *lock);
                void write_sequnlock(seqlock_t *lock);
                など。

你可能感兴趣的:(linux)