相关疑难解决方法(0)

如何避免线程+优化器==无限循环?

在今天的代码审查中,我偶然发现了以下一些代码(稍微修改后发布):

while (!initialized)
{
  // The thread can start before the constructor has finished initializing the object.
  // Can lead to strange behavior. 
  continue;
}
Run Code Online (Sandbox Code Playgroud)

这是在新线程中运行的前几行代码.在另一个线程中,一旦初始化完成,它就会设置initializedtrue.

我知道优化器可以将其变成无限循环,但是避免这种情况的最佳方法是什么?

  • volatile- 被认为有害
  • 调用isInitialized()函数而不是直接使用变量 - 这会保证内存障碍吗?如果宣布该功能inline怎么办?

还有其他选择吗?

编辑:

应该早点提到这一点,但这是需要在Windows,Linux,Solaris等上运行的可移植代码.我们主要使用Boost.Thread作为我们的便携式线程库.

c++ multithreading thread-safety compiler-optimization

3
推荐指数
1
解决办法
536
查看次数

多个线程可以读取同一个类成员变量吗?

多个线程可以安全地读取同一个类成员变量而不产生竞争条件吗?

class foo {
    int x;
};

void Thread1(foo* bar) {
    float j = bar->x * 5;
}

void Thread2(foo* bar) {
    float k = bar->x / 5;
}
Run Code Online (Sandbox Code Playgroud)

因此,例如,如果我们有两个线程正在运行,Thread1并且Thread2. 如果每个线程都传递同一个 foo对象,它们是否可以独立运行,没有竞争条件,因为我们只是读取变量而不是写入?还是访问对象的行为使整个事情变得不安全?

如果以上安全的,第三个线程是否可以安全地写入同一个foo对象,只要它不接触foo::x

#include <thread>

class foo {
public:
    int x = 1;
    int y = 1;
};

void Thread1(foo* bar) {
    int j;
    for (int i = 0; i < 1000; i++) {
        j = …
Run Code Online (Sandbox Code Playgroud)

c++ thread-safety

2
推荐指数
1
解决办法
625
查看次数

受限是 volatile 的对立面吗?

我可以使用volatile类似以下的内容,其中的值可能会被外部函数/信号/等修改:

volatile int exit = 0;
while (!exit)
{
    /* something */
}
Run Code Online (Sandbox Code Playgroud)

并且编译器/程序集不会缓存该值。另一方面,使用restrict关键字,我可以告诉编译器一个变量没有别名/只在当前范围内被引用一次,编译器可以尝试优化它:

void update_res (int *a , int *b, int * restrict c ) {
    * a += * c;
    * b += * c;
}
Run Code Online (Sandbox Code Playgroud)

这是对两者的正确理解,它们基本上是彼此对立的吗?volatile说该变量可以在当前范围之外修改并restrict说它不能?对于使用这两个关键字的最基本示例,它将发出的汇编指令示例是什么?

c x86 assembly volatile restrict-qualifier

2
推荐指数
1
解决办法
187
查看次数

Windows 上*单 CPU*(多核)上的 C++ 多线程是否存在“缓存一致性”问题?

(编辑:只是为了澄清:“缓存一致性”的问题是在不使用原子变量的情况下。)

是否有可能(单CPU情况:Windows可以在Intel / AMD / Arm CPU上运行),线程1运行在core-1上存储一个bool变量(例如)并且它保留在L1缓存中,而线程2在 core-n 上运行使用该变量,并且它会查找内存中该变量的另一个副本?

代码示例(为了演示该问题,我们假设这std::atomic_bool只是一个普通的bool):

#include <thread>
#include <atomic>
#include <chrono>

std::atomic_bool g_exit{ false }, g_exited{ false };

using namespace std::chrono_literals;

void fn()
{
    while (!g_exit.load(std::memory_order_acquire))
    {
        // do something (lets say it takes 1-4s, repeatedly)
        std::this_thread::sleep_for(1s);
    }

    g_exited.store(true, std::memory_order_release);
}

int main()
{
    std::thread wt(fn);
    wt.detach();

    // do something (lets say it took 2s)
    std::this_thread::sleep_for(2s);

    // Exit

    g_exit.store(true, std::memory_order_release);

    for (int i = 0; i < 5; …
Run Code Online (Sandbox Code Playgroud)

c++ multithreading cpu-architecture memory-barriers stdatomic

2
推荐指数
1
解决办法
1079
查看次数

对全局变量的多线程访问:我应该使用互斥锁吗

假设我有 2 个线程:std::thread thd1; std::thread thd2;线程 thd1 定期设置一些调用以下setFlag函数的全局变量:

static std::int32_t g_flag;
static std::mutex io_mutex;

void setFlag( std::int32_t flag )
{
   //std::lock_guard<std::mutex> lk(io_mutex);
   g_flag = flag;
}
Run Code Online (Sandbox Code Playgroud)

线程 thd2 定期读取此标志

std::int32_t getFlag()
{
   //std::lock_guard<std::mutex> lk(io_mutex);
   return g_flag;
}
Run Code Online (Sandbox Code Playgroud)

问题是 - 在这种情况下我应该使用互斥锁吗?在没有互斥锁的情况下从多个线程以读写方式访问变量是否安全?

c++ multithreading

1
推荐指数
1
解决办法
73
查看次数

假设在没有锁定的线程中更改全局 bool 变量是崩溃安全的是否安全?

我知道这是未定义的行为。因此存在数据竞争或崩溃的可能性。可以使用atomicbool来避免这种可能性。我有兴趣了解有关碰撞安全的信息。

AFAIU,当一个线程读取另一个线程部分写入或撕裂的值时,可能会发生崩溃。另一方面, bool 的大小是由实现定义的,但让它大于数据模型中指针的大小几乎没有意义。

假设 bool 的内存块将被更新或不更新是否安全?因此,其他线程无法读取撕裂值,因此从不同线程读取/写入全局布尔值是安全的吗?

c++ multithreading boolean c++11

1
推荐指数
1
解决办法
109
查看次数

Java指令重排序和CPU内存重排序

这是一个后续问题

如何演示Java指令重排序问题?

有很多文章和博客提到 Java 和 JVM 指令重新排序,这可能会导致用户操作中出现反直觉的结果。

当我要求演示 Java 指令重新排序导致意外结果时,有几条评论说,更普遍的关注领域是内存重新排序,并且很难在 x86 CPU 上进行演示。

指令重新排序只是内存重新排序、编译器优化和内存模型等更大问题的一部分吗?这些问题真的是 Java 编译器和 JVM 特有的吗?它们是否特定于某些 CPU 类型?

java cpu-architecture memory-barriers instruction-reordering

1
推荐指数
1
解决办法
515
查看次数

x86 上是否需要 std::memory_order_acquire 栅栏?

鉴于 x86 具有强大的内存模型,是否有必要使用std::memory_order_acquirefence(不是 operation)?

例如,如果我有这个代码:

uint32_t read_shm(const uint64_t offset) {
   // m_head_memory_location is char* pointing to the beginning of a mmap-ed named shared memory segment
   // a different process on different core will write to it.
   return *(uint32_t*)(m_head_memory_location + offset);
}
....
int main() {
     uint32_t val = 0;
     while (0 != (val = shm.read(some location)));
     .... // use val
}
Run Code Online (Sandbox Code Playgroud)

我真的需要std::atomic_thread_fence(std::memory_order_acquire)在return语句之前吗?

我觉得没有必要,因为上面代码的目标是尝试从 读取前 4 个字节m_head_memory_location + offset,因此重新排序栅栏后的任何内存操作都不会影响结果。

或者有一些副作用使获取栅栏变得必要?

在 x86 上是否需要获取栅栏(不是操作)? …

c++ x86 memory-barriers c++11 stdatomic

0
推荐指数
1
解决办法
186
查看次数

原子&lt;int&gt;和int之间的区别

我想知道我们是否只是进行加载和存储之间是否有任何std::atomic<int>不同int。我不关心内存顺序。例如考虑下面的代码

int x{1};

void f(int myid) {

    while(1){
        while(x!= myid){}
        //cout<<"thread : "<< myid<<"\n";
        //this_thread::sleep_for(std::chrono::duration(3s));
        x = (x % 3) + 1;
    }
}

int main(){

    thread x[3];
    for(int i=0;i<3;i++){

        x[i] = thread(f,i+1);
    }

    for(int i=0;i<3;i++){

        x[i].join();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在输出(如果取消注释 cout)将是

线程:1

螺纹数:2

螺纹数:3

...

int x我想知道更改为有什么好处吗atomic<int> x

c++ c++11 stdatomic

0
推荐指数
1
解决办法
1362
查看次数

读取原子修改的值是否需要内存屏障?

鉴于以下情况:

class Foo
{
public:
    void Increment()
    {
        _InterlockedIncrement(&m_value); // OSIncrementAtomic
    }

    long GetValue()
    {
        return m_value;
    }

private:
    long m_value;
};
Run Code Online (Sandbox Code Playgroud)

读取时是否需要内存屏障m_value?我的理解是,这_InterlockedIncrement将生成完整的内存屏障,并确保在发生任何后续加载之前存储该值。因此,从这方面来看,这听起来很安全,但是,m_value完全可以缓存,即可以GetValue()返回陈旧的值,即使在原子递增时也是如此?

Jeff Preshing 的优秀文章供参考:https://preshing.com/20120515/memory-reordering-caught-in-the-act/

其他上下文: 我正在关注一系列有关无锁编程的文章,特别是查看变量的用法unfinishedJobs以及此处的潜在实现HasJobCompleted: https: //blog.molecular-matters.com/2015/08 /24/job-system-2-0-lock-free-work-stealing-part-1-basics/

void Wait(const Job* job)
{
  // wait until the job has completed. in the meantime, work on any other job.
  while (!HasJobCompleted(job))
  {
    Job* nextJob = GetJob();
    if (nextJob)
    {
      Execute(nextJob);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

可以通过将 unfinishedJobs …

c++ winapi multithreading atomic lock-free

0
推荐指数
1
解决办法
929
查看次数