我经常发现这些术语在并发编程的上下文中使用.它们是相同的还是不同的?
我编写了一个简单的多线程程序,如下所示:
static bool finished = false;
int func()
{
size_t i = 0;
while (!finished)
++i;
return i;
}
int main()
{
auto result=std::async(std::launch::async, func);
std::this_thread::sleep_for(std::chrono::seconds(1));
finished=true;
std::cout<<"result ="<<result.get();
std::cout<<"\nmain thread id="<<std::this_thread::get_id()<<std::endl;
}
Run Code Online (Sandbox Code Playgroud)
它通常表现在调试模式下在Visual Studio中或-O0在GC c和后打印出的结果1秒钟。但是它卡住了,在“ 释放”模式或中不打印任何内容-O1 -O2 -O3。
我正在学习编程的重入性。在IBM 的这个站点上(非常好)。我已经建立了一个代码,复制在下面。这是第一个在网站上滚动的代码。
该代码尝试通过打印在“危险上下文”中不断变化的两个值来显示涉及在文本程序的非线性开发(异步性)中共享访问变量的问题。
#include <signal.h>
#include <stdio.h>
struct two_int { int a, b; } data;
void signal_handler(int signum){
printf ("%d, %d\n", data.a, data.b);
alarm (1);
}
int main (void){
static struct two_int zeros = { 0, 0 }, ones = { 1, 1 };
signal (SIGALRM, signal_handler);
data = zeros;
alarm (1);
while (1){
data = zeros;
data = ones;
}
}
Run Code Online (Sandbox Code Playgroud)
当我尝试运行代码时出现问题(或者更好,没有出现)。我在默认配置中使用 gcc 版本 6.3.0 20170516 (Debian 6.3.0-18+deb9u1)。不会发生被误导的输出。获得“错误”对值的频率为 0!
到底发生了什么?为什么使用静态全局变量重入没有问题?
我正在使用线程清理程序运行boost 无锁队列文档中给出的 MPMC 示例,令我惊讶的是,这个基本示例包含按照 TSan 的数据竞争。知道可能出了什么问题吗?
OS: Red Hat Enterprise Linux Server release 7.7 / Ubuntu 18.04.4
Compiler: g++ (GCC) 9.3.1 20200408 (Red Hat 9.3.1-2) / g++ (Ubuntu 11.1.0-1ubuntu-18.04.1) 11.1.0
CPU Architecture: x86_64
Boost Version: 1.79
Run Code Online (Sandbox Code Playgroud)
TSan 的输出如下:
@vishal: g++ testQ.cpp -lboost_thread -L /usr/local/lib/ -pthread -fsanitize=thread -ggdb3 -fPIE -pie
@vishal: TSAN_OPTIONS="history_size=7" ./a.out
boost::lockfree::queue is lockfree
==================
WARNING: ThreadSanitizer: data race (pid=22019)
Atomic write of size 8 at 0x7b1000001c00 by thread T1:
#0 __tsan_atomic64_store <null> (libtsan.so.0+0x800ca)
#1 std::atomic<boost::lockfree::detail::tagged_ptr<boost::lockfree::queue<int>::node> >::store(boost::lockfree::detail::tagged_ptr<boost::lockfree::queue<int>::node>, …Run Code Online (Sandbox Code Playgroud) 考虑这个代码,where x和y是整数:
if (x)
y = 42;
Run Code Online (Sandbox Code Playgroud)
是否允许以下编译器转换?
int tmp = y;
y = 42;
if (!x)
y = tmp;
Run Code Online (Sandbox Code Playgroud)
背景:
这是来自Bjarne Stroustrup的FAQ:
// start with x==0 and y==0
if (x) y = 1; // Thread 1
if (y) x = 1; // Thread 2
Run Code Online (Sandbox Code Playgroud)
常见问题解答说这是数据竞争免费; 使用x和y0都不应该写入任何变量.
但如果允许转换怎么办?
我在测试我的项目时遇到了数据竞争警告,想知道是否有人愿意帮助我解决这个问题。我过去从未尝试过测试 go 例程,并且发现很难理解数据竞争。
我在描述中提供了未解决问题的链接,并在问题描述中提供了跟踪。
我真的很感激一些帮助,只是从学习调试类似问题和将来为 go 例程编写更好的测试方面来看。
https://github.com/nitishm/vegeta-server/issues/52
下面还提供了跟踪片段
=== RUN Test_dispatcher_Cancel_Error_completed
INFO[0000] creating new dispatcher component=dispatcher
INFO[0000] starting dispatcher component=dispatcher
INFO[0000] dispatching new attack ID=d63a79ac-6f51-486e-845d-077c8c76168a Status=scheduled component=dispatcher
==================
WARNING: DATA RACE
Read at 0x00c0000f8d68 by goroutine 8:
vegeta-server/internal/dispatcher.(*task).Complete()
/Users/nitishm/vegeta-server/internal/dispatcher/task.go:116 +0x61
vegeta-server/internal/dispatcher.run()
/Users/nitishm/vegeta-server/internal/dispatcher/task.go:213 +0x17a
Previous write at 0x00c0000f8d68 by goroutine 7:
vegeta-server/internal/dispatcher.(*task).Run()
/Users/nitishm/vegeta-server/internal/dispatcher/task.go:107 +0x12a
vegeta-server/internal/dispatcher.(*dispatcher).Run()
/Users/nitishm/vegeta-server/internal/dispatcher/dispatcher.go:109 +0xb5f
Goroutine 8 (running) created at:
vegeta-server/internal/dispatcher.(*task).Run()
/Users/nitishm/vegeta-server/internal/dispatcher/task.go:105 +0x11c
vegeta-server/internal/dispatcher.(*dispatcher).Run()
/Users/nitishm/vegeta-server/internal/dispatcher/dispatcher.go:109 +0xb5f
Goroutine 7 (running) created at:
vegeta-server/internal/dispatcher.Test_dispatcher_Cancel_Error_completed()
/Users/nitishm/vegeta-server/internal/dispatcher/dispatcher_test.go:249 +0x545
testing.tRunner()
/usr/local/go/src/testing/testing.go:827 +0x162
================== …Run Code Online (Sandbox Code Playgroud) 我有 NetworkProvider,它将连续调用 api,并且一旦我收到数据,我将更新用户 ID。同时我将从其他功能访问用户ID。
这是数据竞争条件,有人可以帮助消除该条件。
`
class NetworkProvider {
public var userID: String
func observeStateChange() {
FIRAuth.auth()?.addStateDidChangeListener({ (auth, authenticatedUser) in
if let user = authenticatedUser {
userID = user.uid
}
}
}
func currentUserID() -> String {
return self.userID
}
}`
Run Code Online (Sandbox Code Playgroud) 多个线程可以安全地同时将相同的值写入相同的变量吗?
对于一个特定的例子——下面的代码是否由 C++ 标准保证编译,在没有未定义行为的情况下运行并在每个符合标准的系统上打印“true”?
#include <cstdio>
#include <thread>
int main()
{
bool x = false;
std::thread one{[&]{ x = true; }};
std::thread two{[&]{ x = true; }};
one.join();
two.join();
std::printf(x ? "true" : "false");
}
Run Code Online (Sandbox Code Playgroud)
这是一个理论问题;我想知道它是否总是有效,而不是在实践中是否有效(或者编写这样的代码是否是个好主意:))。如果有人能指出标准的相关部分,我将不胜感激。根据我的经验,它在实践中总是有效,但不知道它是否保证有效,我总是使用它std::atomic- 我想知道这对于这种特定情况是否绝对必要。
(假设:int x{ 6 }并且2个评价x = 6同时写入)
--
CPP 参考资料中提到内存模型:线程和数据竞争:
当一个表达式的计算写入一个内存位置而 另一个计算读取或修改同一内存位置时,这些表达式被称为冲突。具有两个相互冲突的评估的程序会发生数据竞争,除非:
两个评估在同一线程或同一信号处理程序中执行,或者
两个相互冲突的求值都是原子操作(参见 std::atomic),或者
一个相互冲突的评估发生在另一个评估之前(请参阅 std::memory_order)。
如果发生数据竞争,则程序的行为是不确定的。
参考文献说:“另一评价修改”;它没有说“另一篇评论写道”。
--
C++ 标准关于6.9.2.2 数据竞争的规定:
- 如果两个表达式求值之一修改内存位置 ([intro.memory]),而另一个表达式求值读取或 修改同一内存位置,则两个表达式求值会发生冲突。
--
将相同的值重新写入内存位置是否算作修改内存?
我在紧密循环中有两个不同步的线程,将全局变量递增 X 次 (x=100000)。
全局的正确最终值应该是 2*X,但由于它们不同步,所以它会更少,根据经验,它通常只是略高于 X
然而,在所有测试运行中, global 的值从未低于 X 。
最终结果有可能小于x(小于100000)吗?
public class TestClass {
static int global;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread( () -> { for(int i=0; i < 100000; ++i) { TestClass.global++; } });
Thread t2 = new Thread( () -> { for(int i=0; i < 100000; ++i) { TestClass.global++; } });
t.start(); t2.start();
t.join(); t2.join();
System.out.println("global = " + global);
}
}
Run Code Online (Sandbox Code Playgroud) java multithreading synchronization race-condition data-race