C++ C++;/Linux—是否可以将特定于上下文的数据注入到创建的每个线程中

C++ C++;/Linux—是否可以将特定于上下文的数据注入到创建的每个线程中,c++,linux,pthreads,C++,Linux,Pthreads,我有一个应用程序上下文的概念,它是为流程中的某个范围创建和使用的。这个上下文可以包含上下文特定的单例。无论何时创建线程,我都会将上下文传递给线程,以便线程中的所有代码都可以查看相同的上下文。 这一切都很好,但我遇到的问题是,当线程由我无法控制的第三方库创建时 我正试图找到一种方法来拦截我的应用程序中所有线程的创建,这样我就可以确保上下文被传递给所有线程,不管我是否创建了它们。我试图避免截取pthread_create,主要是因为我不想依赖LD_PRELOAD来实现这一点。 如果有某种方法可以获取

我有一个应用程序上下文的概念,它是为流程中的某个范围创建和使用的。这个上下文可以包含上下文特定的单例。无论何时创建线程,我都会将上下文传递给线程,以便线程中的所有代码都可以查看相同的上下文。 这一切都很好,但我遇到的问题是,当线程由我无法控制的第三方库创建时

我正试图找到一种方法来拦截我的应用程序中所有线程的创建,这样我就可以确保上下文被传递给所有线程,不管我是否创建了它们。我试图避免截取pthread_create,主要是因为我不想依赖LD_PRELOAD来实现这一点。 如果有某种方法可以获取线程的“父”线程id,我可以查找父线程的上下文,但看起来不可能这样做。
如果我可以设置一些特定于线程的属性,这些属性将被所有子线程继承,那么这可能会起作用,但我同样看不到任何可行的属性

TLDR;有没有任何可能的方法可以将父线程的上下文传递给我不直接创建的子线程,而不预先加载pthread\u create intercept方法

编辑:我不确定在这里发布什么代码,但这就是我控制线程创建时的样子。我使用自己的thread类,而不是std::thread,它包装要调用的方法并传递上下文:

class thread : public std::thread
{
public:
    thread() {}

    template< class Function, class... Args > 
    explicit thread( Function&& f, Args&&... args ) : thread( "", std::forward<Function>( f ), std::forward<Args>( args )... )
    {}

    template< class Function, class... Args > 
    explicit thread( const char * thread_name, Function&& f, Args&&... args ) : std::thread( thread::wrap<std::decay_t<Function>,std::decay_t<Args>...>,
                                                                                             AppContext::impl(), std::forward<Function>( f ), std::forward<Args>( args )... )
    {
        if( thread_name && *thread_name )
            setThreadName( thread_name );
    }

    void setThreadName( const char * thread_name );

private:
    template< class Function, class... Args > 
    static void wrap( std::weak_ptr<AppContextImpl> impl, Function&& f, Args&&... args )
    {
       AppContext threadContext( impl );
       f( std::forward<Args>( args )... );
    }
};
类线程:公共标准::线程
{
公众:
线程(){}
模板<类函数,类…参数>
显式线程(函数和函数,参数和函数):线程(“,std::forward(f),std::forward(参数)…)
{}
模板<类函数,类…参数>
显式线程(const char*thread_名称、函数和函数、参数和…参数):std::thread(thread::wrap,
AppContext::impl(),std::forward(f),std::forward(args)…)
{
if(线程名称&&*线程名称)
setThreadName(线程名称);
}
void setThreadName(常量字符*线程名称);
私人:
模板<类函数,类…参数>
静态无效换行(std::weak_ptr impl、函数和函数、参数和参数)
{
AppContext-threadContext(impl);
f(标准:正向(参数)…);
}
};

为什么库内部的线程需要您的上下文变量?该线程可能不会运行一行代码,这意味着它也不需要您的数据


因此,最简单的解决方案是在类中包装对该上下文的访问。该类将在第一次访问时实例化上下文的副本。无访问、无上下文创建、无开销。

为什么库内部的线程需要您的上下文变量?该线程可能不会运行一行代码,这意味着它也不需要您的数据


因此,最简单的解决方案是在类中包装对该上下文的访问。该类将在第一次访问时实例化上下文的副本。无访问、无上下文创建、无开销。

带有线程本地存储的变量可以满足您对每个线程具有单独上下文的需求

从所谓的“父”线程上下文初始化此上下文是一个棘手的部分。就我所知,实现这一点的唯一方法是将父上下文传递给在线程上执行的回调。任何使用回调创建线程的合理库都提供了一种至少传递一个指向自定义数据的指针的方法

例如:

struct context {
    const char* name;
};

context& get_context(context* parent_context)
{
    thread_local context
        my_context = parent_context
                   ? *parent_context
                   : context{
                       "initial context"
                   };
   return my_context;
}

void callback(context* parent_context)
{
    assert(parent_context);
    context& my_context = get_context(parent_context);
    std::cout << "callback, before mod:\t\t"
              << my_context.name
              << '\n';

    my_context.name = "context was changed";

    std::cout << "callback, after mod:\t\t"
              <<my_context.name
              << '\n';
}

int main() {
    context& my_context = get_context(nullptr);
    std::cout << "main, before thread:\t\t"
              << my_context.name
              << '\n';

    auto t = std::thread(callback, my_context);
    t.join();

    std::cout << "main, after thread:\t\t"
              << my_context.name
              << '\n';
}
struct上下文{
常量字符*名称;
};
上下文&获取上下文(上下文*父上下文)
{
线程与本地上下文
我的上下文=父上下文
?*父上下文
:上下文{
“初始上下文”
};
返回我的上下文;
}
无效回调(上下文*父上下文)
{
断言(父上下文);
context&my\u context=get\u context(父上下文);

std::cout带有线程本地存储的变量可以满足您对每个线程具有单独上下文的需求

从所谓的“父”线程上下文初始化此上下文是一个棘手的部分。据我所知,实现这一点的唯一方法是将父上下文传递给在线程上执行的回调。任何创建带有回调的线程的合理库都提供了至少传递自定义数据指针的方法

例如:

struct context {
    const char* name;
};

context& get_context(context* parent_context)
{
    thread_local context
        my_context = parent_context
                   ? *parent_context
                   : context{
                       "initial context"
                   };
   return my_context;
}

void callback(context* parent_context)
{
    assert(parent_context);
    context& my_context = get_context(parent_context);
    std::cout << "callback, before mod:\t\t"
              << my_context.name
              << '\n';

    my_context.name = "context was changed";

    std::cout << "callback, after mod:\t\t"
              <<my_context.name
              << '\n';
}

int main() {
    context& my_context = get_context(nullptr);
    std::cout << "main, before thread:\t\t"
              << my_context.name
              << '\n';

    auto t = std::thread(callback, my_context);
    t.join();

    std::cout << "main, after thread:\t\t"
              << my_context.name
              << '\n';
}
struct上下文{
常量字符*名称;
};
上下文&获取上下文(上下文*父上下文)
{
线程与本地上下文
我的上下文=父上下文
?*父上下文
:上下文{
“初始上下文”
};
返回我的上下文;
}
无效回调(上下文*父上下文)
{
断言(父上下文);
context&my\u context=get\u context(父上下文);

std::cout关于thread\u local
?请展示一些您想要的示例代码。第三方库是什么样子的?您听起来好像第三方不允许您指定回调函数的上下文,但是一个小代码可能会更清楚。另外,您可以为第三方指定回调函数本身吗rty?为什么要将“上下文”传递给那些“线程”你这么说是什么意思?如果你有多个上下文,你怎么知道哪一个应该与第三方库创建的线程一起使用?基本上,我的上下文是一个线程局部变量,我想传递给所有子线程。@1201程序如果我要截取pthread\u create,我在创建时知道正确的上下文调用。或者,如果我知道线程“父”线程,我可以查找父线程的本地上下文。
:public std::thread
-为什么?从标准库继承是,