如何保护数据的初始化只在一个线程中进行?

huangapple go评论69阅读模式
英文:

How to guard the initialization of data to one thread?

问题

使用现代C++,在一个线程初始化共享内存,然后被多个线程读取的最佳方式是什么?它需要尽可能轻量化。

int *ptr = nullptr;

void parallel_work() {
    // 这应该只由第一个到达这一点的线程执行
    ptr = init_ptr();

    // 在ptr设置之后,所有线程都可以进行读取
    do_with(ptr);
}

int main() {
    std::thread th0 { &parallel_work };
    std::thread th1 { &parallel_work };
    std::thread th2 { &parallel_work };
    parallel_work();
}

如果可能的话,我真的想避免在代码的整个读取部分包装一个mutex

附注:这不是使用static函数变量的用例,因为我将在程序的生命周期中创建许多这样的变量。

英文:

Using modern C++, what is the best way to have some shared memory that is initialized by one thread, the first to get to this point, and then read by many threads? It needs to be as lightweight as possible.

int *ptr = nullptr;

void parallel_work() {
    // this should only done by the first thread to this point
    ptr = init_ptr();

    // all threads read After ptr is set 
    do_with(ptr);
}


int main() {
    std::thread th0 { &parallel_work };
    std::thread th1 { &parallel_work };
    std::thread th2 { &parallel_work };
    parallel_work();
}

If it can help, I really want to avoid wrapping the whole read part of the code in a mutex.

PS: this is not the use case for static function variables, as I'll be creating many of these in the program's lifetime.

答案1

得分: 8

std::call_once 的作用如下。

int *ptr = nullptr;
std::once_flag flag;

void parallel_work() {
    std::call_once(&flag, []() {
        ptr = init_ptr();
    });

    do_with(ptr);
}

它甚至会强制其他线程等待,直到 init_ptr 完成,并确保它们都看到 ptr 的已初始化值。

英文:

std::call_once does exactly this.

int *ptr = nullptr;
std::once_flag flag;

void parallel_work() {
    std::call_once(&flag, []() {
        ptr = init_ptr();
    });

    do_with(ptr);
}

It even forces other threads to wait until init_ptr is done and it synchronizes to make sure they all see the initialized value of ptr.

答案2

得分: 0

ptr 变成一个本地静态变量。

int* get_ptr() {
  static int *ptr = init_ptr();
  return ptr;
}

void parallel_work() {
  // 所有线程在 ptr 被设置之后读取
  do_with(get_ptr());
}
英文:

As I commented, make ptr a local static variable.

int* get_ptr() {
  static int *ptr = init_ptr();
  return ptr;
}

void parallel_work() {
  // all threads read After ptr is set 
  do_with(get_ptr());
}

</details>



# 答案3
**得分**: -1

Scott Mayer的单例会做。只需将静态对象放在一个函数内:
```C++
result_t& single () {
    static result_t res{ /*初始化参数*/ };
    return res;
};

编译器通过隐藏的once_flag对象或类似的魔术,在第一次调用ownin函数时管理初始化。

英文:

Scott Mayer's singleton will do. Just put the statc object inside a function:

result_t&amp; single (){
    static result_t res{ /*initialization parameters*/};
    return res;
};

Compiler manages the initialization on 1st call of the ownin function, via a hidden once_flag object or similar magic.

huangapple
  • 本文由 发表于 2023年3月7日 23:44:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/75664155.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定