我在 OpenCL 1.2 中遇到问题。__global看,我有一个内核中的数组,组大小为 1000。问题是该atomic_add()函数无法正常工作。
我的内核代码是:
__kernel void kernelfunction(__global uint32_t* buffer){
buffer[3] = 100;
atomic_add(&buffer[3], 1);
...
}
Run Code Online (Sandbox Code Playgroud)
如果我创建 1000 个线程,我预计 的值buffer[3]将是 1100,对吗?但程序的行为是未定义的。有时会是 1100,有时是 1064,有时是 1093,...
我尝试过的:
我还启用了 opencl 扩展,如下所示:
#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable
但问题依然存在。在另一个项目中,我创建了一个简单的 opencl 项目并且工作atomic_add正常,并且我检查了几乎整个项目配置,但我不知道问题出在哪里。
你能帮助我吗?谢谢
这是有关C ++标准的形式保证的问题。
该标准指出,std::memory_order_relaxed原子变量规则允许“凭空” /“出乎意料”的值出现。
但是对于非原子变量,这个例子可以有UB吗?是否r1 == r2 == 42有可能在C ++抽象机?== 42最初都不是变量,因此您不希望任何if主体执行,这意味着不会写入共享变量。
// Global state
int x = 0, y = 0;
// Thread 1:
r1 = x;
if (r1 == 42) y = r1;
// Thread 2:
r2 = y;
if (r2 == 42) x = 42;
Run Code Online (Sandbox Code Playgroud)
上面的示例改编自标准,该标准明确表示原子对象规范允许这种行为:
[注意:在以下示例中,要求确实允许r1 == r2 == 42,而x和y最初为零:
Run Code Online (Sandbox Code Playgroud)// Thread 1: r1 = x.load(memory_order_relaxed); if (r1 == 42) y.store(r1, memory_order_relaxed); // …
这是我运行的代码:
package main
import (
"fmt"
"time"
)
const delay = 9 * time.Millisecond
func main() {
n := 0
go func() {
time.Sleep(delay)
n++
}()
fmt.Println(n)
}
Run Code Online (Sandbox Code Playgroud)
这是我使用的命令:
go run -race data_race_demo.go
Run Code Online (Sandbox Code Playgroud)
这是我注意到的行为:
delay设定为9ms或更低,种族数据一直检测(程序引发Found 1 data race(s))delay设定为12毫秒以上,种族数据从未检测(程序简单的打印0)delay设置为10至11毫秒,数据争用间断地出现(即,有时打印0有时抛出Found 1 data race(s))为什么会在 10-11ms 左右发生这种情况?
darwin/amd64如果这很重要,我正在使用 Go 1.16.3 。
cppreference.com说:
线程和数据竞争
当一个表达式的求值修改到一个内存位置而另一个求值读取或修改相同的内存位置时,这些表达式被称为冲突。具有两个相互冲突的评估的程序会发生数据竞争,除非......
这谈到了“thread1-modify thread2-read”(MR) 的场景以及“thread1-modify thread2-modify”(MM) 的场景。
“线程 1 读取线程 2 读取”(RR) 怎么样?
这个问题是我上一个问题的延续,我的理解是“ A data race is a property of an execution, not of the program in the abstract”,这意味着只要 2 个线程不访问共享变量(至少有一个是写访问),实际上而不仅仅是理论上,那么程序的行为将得到很好的定义。
根据上述理解,我想讨论以下方案:
#include <iostream>
#include <thread>
#include <unistd.h>
constexpr int sleepTime = 10;
void func(int* ptr) {
sleep(sleepTime);
std::cout<<"going to delete ptr: "<<(uintptr_t)ptr<<"\n";
delete ptr;
std::cout<<"ptr has been deleted\n";
}
int main() {
int* l_ptr = new int(5);
std::thread t(func, l_ptr);
t.detach();
std::cout<<"We have passed ptr: "<<(uintptr_t)l_ptr<<" to thread for deletion. Val at ptr: "<<*l_ptr<<"\n";
std::cin.get();
}
Run Code Online (Sandbox Code Playgroud)
上面的程序包含数据竞争,当且仅当“主线程”和“子线程”碰巧同时访问共享变量时。 …
有人可以解释以下程序的输出:
public class DataRace extends Thread {
static ArrayList<Integer> arr = new ArrayList<>();
public void run() {
Random random = new Random();
int local = random.nextInt(10) + 1;
arr.add(local);
}
public static void main(String[] args) {
DataRace t1 = new DataRace();
DataRace t2 = new DataRace();
DataRace t3 = new DataRace();
DataRace t4 = new DataRace();
t1.start();
t2.start();
t3.start();
t4.start();
try {
t1.join();
t2.join();
t3.join();
t4.join();
} catch (InterruptedException e) {
System.out.println("interrupted");
}
System.out.println(DataRace.arr);
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
java parallel-processing concurrency multithreading data-race
我制作了一个自定义属性包装器,它提供了一种使用os_unfair_lock. 在启用 TSAN 的情况下测试我的包装器后,在使用锁定获取时报告了访问争用错误os_unfair_lock_lock(如下图所示)
不知何故,TSAN 报告认为线程安全的锁定结构并非如此。这里发生了什么?
当我学习 C++ 时,我发现了一些奇怪的东西......
我认为下面的代码会产生大数的结果(至少不是 1.1)。
相反,结果是在此处输入图像描述
其他编译器按预期工作。
但是具有积极优化的 clang 编译器似乎忽略了 while 循环。
所以我的问题是,我的代码有什么问题?还是clang有意为之?
我使用了apple clang编译器(v14.0.3)
#include <iostream>
#include <thread>
static bool should_terminate = false;
void infinite_loop() {
long double i = 1.1;
while(!should_terminate)
i *= i;
std::cout << i;
}
int main() {
std::thread(infinite_loop).detach();
std::cout << "main thread";
for (int i = 0 ; i < 5; i++) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << ".";
}
should_terminate = true;
}
Run Code Online (Sandbox Code Playgroud)
来自编译器资源管理器的汇编结果(clang v16.0.0,-O3)
这似乎也跳过了 while 循环。
_Z13infinite_loopv: # @_Z13infinite_loopv
sub rsp, 24 …Run Code Online (Sandbox Code Playgroud) 为什么此代码会导致数据争用?我已经使用了原子添加。
package main
import (
"sync/atomic"
"time"
)
var a int64
func main() {
for {
if a < 100 {
atomic.AddInt64(&a, 1)
go run()
}
}
}
func run() {
<-time.After(5 * time.Second)
atomic.AddInt64(&a, -1)
}
Run Code Online (Sandbox Code Playgroud)
我go run --race用这段代码运行命令并得到:
==================
WARNING: DATA RACE
Write at 0x000001150f30 by goroutine 8:
sync/atomic.AddInt64()
/usr/local/Cellar/go/1.11.2/libexec/src/runtime/race_amd64.s:276 +0xb
main.run()
/Users/flask/test.go:22 +0x6d
Previous read at 0x000001150f30 by main goroutine:
main.main()
/Users/flask/test.go:12 +0x3a
Goroutine 8 (running) created at:
main.main()
/Users/flask/test.go:15 +0x75
==================
Run Code Online (Sandbox Code Playgroud)
你能帮我解释一下吗?以及如何解决这个警告?谢谢!
我有一个三重嵌套循环,我想并行化,但是,我遇到了数据争用问题。我很确定我需要以某种方式使用缩减,但我不太知道如何使用。
这是有问题的循环:
#pragma omp parallel for simd collapse(3)
for (uint64 u = 0; u < nu; ++u) {
for (uint64 e = 0; e < ne; ++e) {
for (uint64 v = 0; v < nv; ++v) {
uAT[u][e] += _uT[u][e][v] * wA[e][v];
}
}
}
Run Code Online (Sandbox Code Playgroud)
有人可以向我解释一下,为什么这会导致数据竞争?我真的很想了解这一点,这样我将来就不会遇到这些问题。另外,这个循环可以并行吗?如果是这样,怎么办?
编辑:我怎么知道存在数据竞争?
这个循环应该完成的任务(并且它是串行完成的)是计算不连续伽辽金框架中函数的元素平均值。当我多次运行代码时,有时会得到不同的结果,尽管它应该总是产生相同的结果。产生的错误值总是小于应有的值,这就是为什么我假设某些值没有被添加。也许这张图可以更好地解释它:第三个单元格中的平均值显然是错误的(太小)。
