进程专属密钥环中线程无法互见数据的问题排查
进程密钥环(KEY_SPEC_PROCESS_KEYRING)线程间共享异常问题
我尝试在一个线程中向KEY_SPEC_PROCESS_KEYRING写入密钥,另一个线程读取,但发现每个线程只能读取自己创建的密钥,表现得和KEY_SPEC_THREAD_KEYRING一致。更新代码后发现,只有主线程先调用add_key,子线程才能共享读取该密钥。请问这是内核bug还是操作有误?
初始代码
#include <mutex> #include <thread> #include <iostream> #include <keyutils.h> int main() { std::mutex m; auto f = [&]() { std::lock_guard lock(m); std::cout << "-----" << std::endl; key_serial_t ring = KEY_SPEC_PROCESS_KEYRING; const char* type = "user"; const char* name = "test"; long key = keyctl_search(ring, type, name, 0); std::cout << "get: " << key << std::endl; if (key == -1) { key = add_key(type, name, "1", 2, ring); std::cout << "set: " << key << std::endl; key = keyctl_search(ring, type, name, 0); std::cout << "get: " << key << std::endl; } }; std::thread t1(f); std::thread t2(f); t1.join(); t2.join(); return 0; }
初始输出(Ubuntu 24.04)
----- get: -1 set: 979097589 get: 979097589 ----- get: -1 set: 534386259 get: 534386259
更新后代码
#include <mutex> #include <thread> #include <iostream> #include <keyutils.h> #include <unistd.h> using std::cout; using std::endl; int main() { std::mutex m; auto f = [&]() { auto s = "thread " + std::to_string(gettid()) + ": "; { std::lock_guard lock(m); key_serial_t ring = KEY_SPEC_PROCESS_KEYRING; const char* type = "user"; const char* name = "test"; long key = keyctl_search(ring, type, name, 0); cout << s << "get: " << key << endl; if (key == -1) { // perror("key"); key = add_key(type, name, "1", 2, ring); cout << s << "set: " << key << endl; key = keyctl_search(ring, type, name, 0); cout << s << "get: " << key << endl; } } using namespace std::chrono_literals; std::this_thread::sleep_for(1s); std::lock_guard lock(m); cout << s << "end" << endl; }; std::thread t1(f); std::thread t2(f); t1.join(); t2.join(); cout << "---" << endl; f(); cout << "---" << endl; std::thread t3(f); std::thread t4(f); t3.join(); t4.join(); return 0; }
更新后输出
thread 39192: get: -1 thread 39192: set: 296360159 thread 39192: get: 296360159 thread 39193: get: -1 thread 39193: set: 186733216 thread 39193: get: 186733216 thread 39193: end thread 39192: end --- thread 39191: get: -1 thread 39191: set: 844445250 thread 39191: get: 844445250 thread 39191: end --- thread 39195: get: 844445250 thread 39196: get: 844445250 thread 39196: end thread 39195: end
问题解答
这不是内核bug,是对进程密钥环的初始化逻辑理解有误。
Linux的进程密钥环(process keyring)默认采用延迟创建机制:只有当进程(或线程)首次主动访问它时,内核才会为该进程实例化进程密钥环。
核心逻辑拆解:
- 初始代码和更新代码前半段中,主线程从未主动访问过进程密钥环,由子线程
t1、t2首次调用add_key/keyctl_search触发密钥环创建。但此时内核只是为当前线程临时创建了进程密钥环,并未将其标记为进程全局共享的密钥环——直到主线程首次访问,内核才会完成进程密钥环的全局初始化,绑定到整个进程。 - 当主线程调用
f()(更新代码中间部分)时,主线程首次访问进程密钥环,此时内核完成全局初始化,后续创建的子线程t3、t4会自动继承这个已初始化的进程密钥环,因此能读取到主线程创建的密钥。
修复方法
在程序启动时,让主线程提前触发进程密钥环的初始化即可,比如在创建子线程前执行一次空搜索:
int main() { // 提前初始化进程密钥环,确保后续子线程共享同一个环 keyctl_search(KEY_SPEC_PROCESS_KEYRING, "user", "dummy_init", 0); std::mutex m; // 后续代码保持不变... }
这样所有子线程都会共享同一个进程密钥环,不会再出现各自创建独立密钥的情况。
内容的提问来源于stack exchange,提问作者enburk
相关产品推荐
相关产品推荐

