C言語でLinuxカーネルの同期プログラミングを教えて!
こういった悩みにお答えします.
本記事の信頼性
- リアルタイムシステムの研究歴12年.
- 東大教員の時に,英語でOS(Linuxカーネル)の授業.
- 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校(UNC)コンピュータサイエンス学部で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
- プログラミング歴15年以上,習得している言語: C/C++,Python,Solidity/Vyper,Java,Ruby,Go,Rust,D,HTML/CSS/JS/PHP,MATLAB,Verse(UEFN), Assembler (x64,ARM).
- 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」をGitHubにオープンソースとして公開.
- 2020年1月~現在はアメリカのノースカロライナ州チャペルヒルにあるGuarantee Happiness LLCのCTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
- 最近は自然言語処理AIとイーサリアムに関する有益な情報発信に従事.
- (AI全般を含む)自然言語処理AIの論文の日本語訳や,AIチャットボット(ChatGPT,Auto-GPT,Gemini(旧Bard)など)の記事を50本以上執筆.アメリカのサンフランシスコ(広義のシリコンバレー)の会社でプロンプトエンジニア・マネージャー・Quality Assurance(QA)の業務委託の経験あり.
- (スマートコントラクトのプログラミングを含む)イーサリアムや仮想通貨全般の記事を200本以上執筆.イギリスのロンドンの会社で仮想通貨の英語の記事を日本語に翻訳する業務委託の経験あり.
こういった私から学べます.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!
本記事では,以下のLinuxカーネル「同期」を理解していることを前提としています.
目次
【C言語】Linuxカーネルの同期プログラミング
C言語でLinuxカーネルの同期プログラミングを紹介します.
具体的には,以下の内容を解説します.
- アトミック操作(アトミック整数演算,アトミックビット演算)
- スピンロック
- Read-Write Lock
- セマフォ
- Read-Writeセマフォ
- ミューテックス
- Completion
- Sequential Lock(seqlock)
- Read-Copy Update(RCU)
アトミック操作
アトミック操作は,アトミック整数演算とアトミックビット演算のカーネルモジュールのコードを紹介します.
アトミック整数演算
アトミック整数演算のカーネルモジュールのコード一式はこちらからダウンロードして下さい.
atomic_int_kernel_module.cのコードは以下になります.
read_threadがread_func関数,write_threadがwrite_func関数を周期的に呼び出します.
write_func関数でcountをインクリメントし,read_func関数でcountを読み出します.
read_func関数とwrite_func関数は,kthread_should_stop関数の返り値が真になるまで実行します.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/kthread.h> atomic_t count; struct task_struct *read_thread, *write_thread; #define SLEEP_MS 500 static int write_func(void *data) { while (!kthread_should_stop()) { atomic_inc(&count); msleep(SLEEP_MS); } do_exit(0); } static int read_func(void *data) { while (!kthread_should_stop()) { printk("count = %d\n", atomic_read(&count)); msleep(SLEEP_MS); } do_exit(0); } static int __init atomic_int_kernel_module_init(void) { printk("atomic_int_kernel_module_init()\n"); atomic_set(&count, 0); read_thread = kthread_run(read_func, NULL, "read-thread"); write_thread = kthread_run(write_func, NULL, "write-thread"); return 0; } static void __exit atomic_int_kernel_module_exit(void) { printk("atomic_int_kernel_module_exit()\n"); kthread_stop(read_thread); kthread_stop(write_thread); } module_init(atomic_int_kernel_module_init); module_exit(atomic_int_kernel_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Hiroyuki Chishiro"); MODULE_DESCRIPTION("Atomic Int Kernel Module"); |
実行結果は以下になります.
countの値がインクリメントされていることがわかります.(スレッドの実行タイミングによっては,同じ値が連続したり値が2以上増加したりする場合があります.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ make ... $ sudo insmod atomic_int_kernel_module.ko $ sudo rmmod atomic_int_kernel_module.ko $ sudo dmesg ... [ 103.494989] atomic_int_kernel_module_init() [ 103.495334] count = 0 [ 104.017287] count = 1 [ 104.529700] count = 2 [ 105.040264] count = 3 [ 105.552873] count = 4 [ 106.064704] count = 6 [ 106.577104] count = 7 [ 107.002276] atomic_int_kernel_module_exit() |
アトミックビット演算
アトミックビット演算のカーネルモジュールのコード一式はこちらからダウンロードして下さい.
atomic_bitwise_kernel_module.cのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> static int __init atomic_bitwise_kernel_module_init(void) { unsigned long word = 0; printk("atomic_bitwise_kernel_module_init()\n"); set_bit(0, &word); set_bit(1, &word); printk("%lu\n", word); clear_bit(1, &word); change_bit(0, &word); if (test_and_set_bit(0, &word)) { printk("test_and_set_bit() returns true\n"); } else { printk("test_and_set_bit() returns false\n"); } word = 7; printk("%lu\n", word); return 0; } static void __exit atomic_bitwise_kernel_module_exit(void) { printk("atomic_bitwise_kernel_module_exit()\n"); } module_init(atomic_bitwise_kernel_module_init); module_exit(atomic_bitwise_kernel_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Hiroyuki Chishiro"); MODULE_DESCRIPTION("Atomic Bitwise Kernel Module"); |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 |
$ make ... $ sudo insmod atomic_bitwise_kernel_module.ko $ sudo rmmod atomic_bitwise_kernel_module.ko $ sudo dmesg ... [ 1255.293636] atomic_bitwise_kernel_module_init() [ 1255.293639] 3 [ 1255.293639] test_and_set_bit() returns false [ 1255.293640] 7 [ 1256.212262] atomic_bitwise_kernel_module_exit() |
スピンロック
スピンロックのカーネルモジュールのコード一式はこちらからダウンロードして下さい.
spinlock_kernel_module.cのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/kthread.h> int count; DEFINE_SPINLOCK(count_lock); struct task_struct *read_thread, *write_thread; #define SLEEP_MS 500 static int write_func(void *data) { while (!kthread_should_stop()) { spin_lock(&count_lock); count++; spin_unlock(&count_lock); msleep(SLEEP_MS); } do_exit(0); } static int read_func(void *data) { while (!kthread_should_stop()) { spin_lock(&count_lock); printk("count = %d\n", count); spin_unlock(&count_lock); msleep(SLEEP_MS); } do_exit(0); } static int __init spinlock_kernel_module_init(void) { printk("spinlock_kernel_module_init()\n"); count = 0; read_thread = kthread_run(read_func, NULL, "read-thread"); write_thread = kthread_run(write_func, NULL, "write-thread"); return 0; } static void __exit spinlock_kernel_module_exit(void) { printk("spinlock_kernel_module_exit()\n"); kthread_stop(read_thread); kthread_stop(write_thread); } module_init(spinlock_kernel_module_init); module_exit(spinlock_kernel_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Hiroyuki Chishiro"); MODULE_DESCRIPTION("Spinlock Kernel Module"); |
実行結果は以下になります.アトミック整数演算と同様です.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ make ... $ sudo insmod spinlock_kernel_module.ko $ sudo rmmod spinlock_kernel_module.ko $ sudo dmesg ... [ 2419.459558] spinlock_kernel_module_init() [ 2419.460926] count = 0 [ 2419.980631] count = 2 [ 2420.492218] count = 3 [ 2421.005098] count = 3 [ 2421.516723] count = 5 [ 2421.775043] spinlock_kernel_module_exit() |
Read-Write Lock
Read-Write Lockのカーネルモジュールのコード一式はこちらからダウンロードして下さい.
read_write_lock_kernel_module.cのコードは以下になります.
Readerのスレッドが3つ,Writerのスレッドが1つ実行します.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/kthread.h> int count; DEFINE_RWLOCK(count_lock); struct task_struct *read_thread1, *read_thread2, *read_thread3, *write_thread; #define SLEEP_MS 500 static int write_func(void *data) { while (!kthread_should_stop()) { write_lock(&count_lock); count++; write_unlock(&count_lock); msleep(SLEEP_MS); } do_exit(0); } static int read_func(void *data) { while (!kthread_should_stop()) { read_lock(&count_lock); printk("count = %d\n", count); read_unlock(&count_lock); msleep(SLEEP_MS); } do_exit(0); } static int __init read_write_lock_kernel_module_init(void) { printk("read_write_lock_kernel_module_init()\n"); count = 0; read_thread1 = kthread_run(read_func, NULL, "read-thread1"); read_thread2 = kthread_run(read_func, NULL, "read-thread2"); read_thread3 = kthread_run(read_func, NULL, "read-thread3"); write_thread = kthread_run(write_func, NULL, "write-thread"); return 0; } static void __exit read_write_lock_kernel_module_exit(void) { printk("read_write_lock_kernel_module_exit()\n"); kthread_stop(read_thread3); kthread_stop(read_thread2); kthread_stop(read_thread1); kthread_stop(write_thread); } module_init(read_write_lock_kernel_module_init); module_exit(read_write_lock_kernel_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Hiroyuki Chishiro"); MODULE_DESCRIPTION("Read-Write Lock Kernel Module"); |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
$ make ... $ sudo insmod read_write_lock_kernel_module.ko $ sudo rmmod read_write_lock_kernel_module.ko $ sudo dmesg ... [ 3817.456777] read_write_lock_kernel_module_init() [ 3817.457126] count = 0 [ 3817.457243] count = 0 [ 3817.457372] count = 0 [ 3817.968626] count = 1 [ 3817.968750] count = 2 [ 3817.968813] count = 2 [ 3818.480318] count = 2 [ 3818.480340] count = 2 [ 3818.480385] count = 3 [ 3818.992320] count = 3 [ 3818.992322] count = 3 [ 3818.992415] count = 3 [ 3819.504326] count = 4 [ 3819.504633] count = 4 [ 3819.504753] count = 4 [ 3820.017107] count = 5 [ 3820.017107] count = 5 [ 3820.017119] count = 6 [ 3820.214836] read_write_lock_kernel_module_exit() [ 3820.528887] count = 6 [ 3820.528959] count = 7 [ 3821.040527] count = 7 |
セマフォ
セマフォのカーネルモジュールのコード一式はこちらからダウンロードして下さい.
semaphore_kernel_module.cのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/kthread.h> #include <linux/semaphore.h> int count; DEFINE_SEMAPHORE(sem); struct task_struct *read_thread, *write_thread; #define SLEEP_MS 500 static int write_func(void *data) { while (!kthread_should_stop()) { down(&sem); count++; up(&sem); msleep(SLEEP_MS); } do_exit(0); } static int read_func(void *data) { while (!kthread_should_stop()) { down(&sem); printk("count = %d\n", count); up(&sem); msleep(SLEEP_MS); } do_exit(0); } static int __init semaphore_kernel_module_init(void) { printk("semaphore_kernel_module_init()\n"); count = 0; sema_init(&sem, 1); read_thread = kthread_run(read_func, NULL, "read-thread"); write_thread = kthread_run(write_func, NULL, "write-thread"); return 0; } static void __exit semaphore_kernel_module_exit(void) { printk("semaphore_kernel_module_exit()\n"); kthread_stop(read_thread); kthread_stop(write_thread); } module_init(semaphore_kernel_module_init); module_exit(semaphore_kernel_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Hiroyuki Chishiro"); MODULE_DESCRIPTION("Semaphore Kernel Module"); |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ make ... $ sudo insmod semaphore_kernel_module.ko $ sudo rmmod semaphore_kernel_module.ko $ sudo dmesg ... [ 4396.320359] semaphore_kernel_module_init() [ 4396.320536] count = 0 [ 4396.846694] count = 1 [ 4397.359797] count = 2 [ 4397.871372] count = 3 [ 4398.383490] count = 4 [ 4398.895019] count = 5 [ 4399.225226] semaphore_kernel_module_exit() |
Read-Writeセマフォ
Read-Writeセマフォのカーネルモジュールのコード一式はこちらからダウンロードして下さい.
read_write_semaphore_kernel_module.cのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/kthread.h> int count; struct rw_semaphore count_rwsem; struct task_struct *read_thread1, *read_thread2, *read_thread3, *write_thread; #define SLEEP_MS 500 static int write_func(void *data) { while (!kthread_should_stop()) { down_write(&count_rwsem); count++; downgrade_write(&count_rwsem); printk("[write] count = %d\n", count); up_read(&count_rwsem); msleep(SLEEP_MS); } do_exit(0); } static int read_func(void *data) { while (!kthread_should_stop()) { down_read(&count_rwsem); printk("count = %d\n", count); up_read(&count_rwsem); msleep(SLEEP_MS); } do_exit(0); } static int __init read_write_semaphore_kernel_module_init(void) { printk("read_write_semaphore_kernel_module_init()\n"); count = 0; init_rwsem(&count_rwsem); read_thread1 = kthread_run(read_func, NULL, "read-thread1"); read_thread2 = kthread_run(read_func, NULL, "read-thread2"); read_thread3 = kthread_run(read_func, NULL, "read-thread3"); write_thread = kthread_run(write_func, NULL, "write-thread"); return 0; } static void __exit read_write_semaphore_kernel_module_exit(void) { printk("read_write_semaphore_kernel_module_exit()\n"); kthread_stop(read_thread3); kthread_stop(read_thread2); kthread_stop(read_thread1); kthread_stop(write_thread); } module_init(read_write_semaphore_kernel_module_init); module_exit(read_write_semaphore_kernel_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Hiroyuki Chishiro"); MODULE_DESCRIPTION("Read-Write Semaphore Kernel Module"); |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
$ make ... $ sudo insmod read_write_semaphore_kernel_module.ko $ sudo rmmod read_write_semaphore_kernel_module.ko $ sudo dmesg ... [ 6476.033538] read_write_semaphore_kernel_module_init() [ 6476.033726] count = 0 [ 6476.033856] count = 0 [ 6476.033983] count = 0 [ 6476.034106] [write] count = 1 [ 6476.543472] [write] count = 2 [ 6476.543534] count = 2 [ 6476.544170] count = 2 [ 6476.544194] count = 2 [ 6477.055338] [write] count = 3 [ 6477.056412] count = 3 [ 6477.056443] count = 3 [ 6477.056502] count = 3 [ 6477.567967] count = 3 [ 6477.567972] [write] count = 4 [ 6477.568731] count = 4 [ 6477.568832] count = 4 [ 6478.079396] count = 4 [ 6478.079409] [write] count = 5 [ 6478.079419] count = 5 [ 6478.079426] count = 5 [ 6478.333795] read_write_semaphore_kernel_module_exit() [ 6478.591820] [write] count = 6 [ 6478.591834] count = 6 [ 6478.591886] count = 6 [ 6479.104240] [write] count = 7 [ 6479.104248] count = 7 |
ミューテックス
ミューテックスのカーネルモジュールのコード一式はこちらからダウンロードして下さい.
mutex_kernel_module.cのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/kthread.h> int count; DEFINE_MUTEX(count_lock); struct task_struct *read_thread, *write_thread; #define SLEEP_MS 500 static int write_func(void *data) { while (!kthread_should_stop()) { mutex_lock(&count_lock); count++; mutex_unlock(&count_lock); msleep(SLEEP_MS); } do_exit(0); } static int read_func(void *data) { while (!kthread_should_stop()) { mutex_lock(&count_lock); printk("count = %d\n", count); mutex_unlock(&count_lock); msleep(SLEEP_MS); } do_exit(0); } static int __init mutex_kernel_module_init(void) { printk("mutex_kernel_module_init()\n"); count = 0; read_thread = kthread_run(read_func, NULL, "read-thread"); write_thread = kthread_run(write_func, NULL, "write-thread"); return 0; } static void __exit mutex_kernel_module_exit(void) { printk("mutex_kernel_module_exit()\n"); kthread_stop(read_thread); kthread_stop(write_thread); } module_init(mutex_kernel_module_init); module_exit(mutex_kernel_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Hiroyuki Chishiro"); MODULE_DESCRIPTION("Mutex Kernel Module"); |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$ make ... $ sudo insmod mutex_kernel_module.ko $ sudo rmmod mutex_kernel_module.ko $ sudo dmesg ... [ 6997.966110] mutex_kernel_module_init() [ 6997.966450] count = 0 [ 6998.497242] count = 1 [ 6999.009327] count = 2 [ 6999.520997] count = 3 [ 7000.033155] count = 4 [ 7000.546168] count = 6 [ 7001.057731] count = 6 [ 7001.570070] count = 8 [ 7002.072613] mutex_kernel_module_exit() |
Completion
Completionのカーネルモジュールのコード一式はこちらからダウンロードして下さい.
completion_kernel_module.cのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/kthread.h> int count; struct completion comp; struct task_struct *read_thread, *write_thread; #define LIMIT 1000 static int write_func(void *data) { while (count <= LIMIT) { count++; } complete(&comp); do_exit(0); } static int read_func(void *data) { wait_for_completion(&comp); printk("count = %d\n", count); do_exit(0); } static int __init completion_kernel_module_init(void) { printk("completion_kernel_module_init()\n"); count = 0; init_completion(&comp); read_thread = kthread_run(read_func, NULL, "read-thread"); write_thread = kthread_run(write_func, NULL, "write-thread"); return 0; } static void __exit completion_kernel_module_exit(void) { printk("completion_kernel_module_exit()\n"); } module_init(completion_kernel_module_init); module_exit(completion_kernel_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Hiroyuki Chishiro"); MODULE_DESCRIPTION("Completion Kernel Module"); |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 |
$ make ... $ sudo insmod completion_kernel_module.ko $ sudo rmmod completion_kernel_module.ko $ sudo dmesg ... [ 7729.114615] completion_kernel_module_init() [ 7729.115128] count = 1001 [ 7732.866396] completion_kernel_module_exit() |
Sequential Lock(seqlock)
Sequential Lock(seqlock)のカーネルモジュールのコード一式はこちらからダウンロードして下さい.
seqlock_kernel_module.cのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/kthread.h> int count; DEFINE_SEQLOCK(count_lock); struct task_struct *read_thread1, *read_thread2, *read_thread3, *write_thread; #define SLEEP_MS 500 static int write_func(void *data) { while (!kthread_should_stop()) { write_seqlock(&count_lock); count++; write_sequnlock(&count_lock); msleep(SLEEP_MS); } do_exit(0); } static int read_func(void *data) { unsigned long seq; while (!kthread_should_stop()) { do { seq = read_seqbegin(&count_lock); } while (read_seqretry(&count_lock, seq)); printk("count = %d\n", count); msleep(SLEEP_MS); } do_exit(0); } static int __init seqlock_kernel_module_init(void) { printk("seqlock_kernel_module_init()\n"); count = 0; read_thread1 = kthread_run(read_func, NULL, "read-thread1"); read_thread2 = kthread_run(read_func, NULL, "read-thread2"); read_thread3 = kthread_run(read_func, NULL, "read-thread3"); write_thread = kthread_run(write_func, NULL, "write-thread"); return 0; } static void __exit seqlock_kernel_module_exit(void) { printk("seqlock_kernel_module_exit()\n"); kthread_stop(read_thread3); kthread_stop(read_thread2); kthread_stop(read_thread1); kthread_stop(write_thread); } module_init(seqlock_kernel_module_init); module_exit(seqlock_kernel_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Hiroyuki Chishiro"); MODULE_DESCRIPTION("Seqlock Kernel Module"); |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
$ make ... $ sudo insmod seqlock_kernel_module.ko $ sudo rmmod seqlock_kernel_module.ko $ sudo dmesg ... [ 8237.643290] seqlock_kernel_module_init() [ 8237.643595] count = 0 [ 8237.643758] count = 0 [ 8237.643898] count = 0 [ 8238.179451] count = 1 [ 8238.179476] count = 1 [ 8238.179672] count = 2 [ 8238.691257] count = 2 [ 8238.691338] count = 3 [ 8238.691381] count = 3 [ 8239.203429] count = 3 [ 8239.203471] count = 4 [ 8239.203523] count = 4 [ 8239.715486] count = 4 [ 8239.715613] count = 4 [ 8239.715681] count = 4 [ 8240.227833] count = 6 [ 8240.227876] count = 6 [ 8240.227934] count = 6 [ 8240.557670] seqlock_kernel_module_exit() |
Read-Copy Update(RCU)
Read-Copy Update(RCU)のカーネルモジュールのコード一式はこちらからダウンロードして下さい.
rcu_kernel_module.cのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/kthread.h> int count; DEFINE_SPINLOCK(count_lock); struct task_struct *read_thread1, *read_thread2, *read_thread3, *write_thread; #define SLEEP_MS 500 static int write_func(void *data) { while (!kthread_should_stop()) { spin_lock(&count_lock); count++; spin_unlock(&count_lock); msleep(SLEEP_MS); } do_exit(0); } static int read_func(void *data) { while (!kthread_should_stop()) { rcu_read_lock(); printk("count = %d\n", count); rcu_read_unlock(); msleep(SLEEP_MS); } do_exit(0); } static int __init rcu_kernel_module_init(void) { printk("rcu_kernel_module_init()\n"); count = 0; read_thread1 = kthread_run(read_func, NULL, "read-thread1"); read_thread2 = kthread_run(read_func, NULL, "read-thread2"); read_thread3 = kthread_run(read_func, NULL, "read-thread3"); write_thread = kthread_run(write_func, NULL, "write-thread"); return 0; } static void __exit rcu_kernel_module_exit(void) { printk("rcu_kernel_module_exit()\n"); kthread_stop(read_thread3); kthread_stop(read_thread2); kthread_stop(read_thread1); kthread_stop(write_thread); } module_init(rcu_kernel_module_init); module_exit(rcu_kernel_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Hiroyuki Chishiro"); MODULE_DESCRIPTION("RCU Kernel Module"); |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
$ make ... $ sudo insmod rcu_kernel_module.ko $ sudo rmmod rcu_kernel_module.ko $ sudo dmesg ... [ 9236.818468] rcu_kernel_module_init() [ 9236.818729] count = 0 [ 9236.818842] count = 0 [ 9236.818918] count = 0 [ 9237.345517] count = 1 [ 9237.345517] count = 1 [ 9237.345544] count = 1 [ 9237.858024] count = 2 [ 9237.858100] count = 3 [ 9237.858162] count = 3 [ 9238.369464] count = 3 [ 9238.369490] count = 3 [ 9238.369509] count = 3 [ 9238.882184] count = 4 [ 9238.882197] count = 4 [ 9238.882329] count = 4 [ 9239.393507] count = 6 [ 9239.393528] count = 6 [ 9239.393642] count = 6 [ 9239.905944] count = 6 [ 9239.905944] count = 6 [ 9239.905993] count = 7 [ 9240.417613] count = 7 [ 9240.417631] count = 7 [ 9240.417685] count = 7 [ 9240.929860] count = 8 [ 9240.929892] count = 8 [ 9240.929928] count = 8 [ 9241.441598] count = 10 [ 9241.441614] count = 10 [ 9241.441672] count = 10 [ 9241.953301] count = 10 [ 9241.953395] count = 11 [ 9241.954426] count = 11 [ 9242.081565] rcu_kernel_module_exit() [ 9242.466172] count = 11 [ 9242.466198] count = 11 [ 9242.977628] count = 13 |
まとめ
C言語でLinuxカーネルの同期プログラミングを紹介しました.
具体的には,以下を解説しました.
- アトミック操作(アトミック整数演算,アトミックビット演算)
- スピンロック
- Read-Write Lock
- セマフォ
- Read-Writeセマフォ
- ミューテックス
- Completion
- Sequential Lock(seqlock)
- Read-Copy Update(RCU)
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!