You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

进程专属密钥环中线程无法互见数据的问题排查

进程密钥环(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 09:06:03