gpt4 book ai didi

c++ - 从另一个对象指向线程对象 : dangerous?

转载 作者:行者123 更新时间:2023-11-30 03:48:41 25 4
gpt4 key购买 nike

假设有两个对象都继承自 thread 父类“utility thread that uses pthreads”。

class Othread1: public thread
{
public:
start() { /* launch thread at 10 Hz */ };
end();
void setvar(float vr) {var2= vr } ;
protected :
float var1;
}

class Othread2: public thread
{
start() { /* launch the thread at 1000 Hz */ } ;
end();
float getvar() { return var2 } ;
protected :
float var2;
}

有没有我们可以做到这一点的事情?

void threadManager(thread *th1, thread *th2)
{
float vtemp = th2->getvar();
th1->setvar(vtemp);
}

int main ()
{
thread th1;
thread th2;
threadManager(&th1,&th2);
return 0;
}

这样的线程间数据使用安全吗?或者我是否必须使用生产者/消费者模式进行队列来交换数据?

最佳答案

我仍然不完全确定您要尝试做什么,但这里有一个示例,希望对您有所帮助。

如果你想在一个线程中读取同时在另一个线程中写入的数据,你需要同步,否则你将调用未定义的行为。 “写作事件”和“阅读事件”之间的时间是多是少并不重要。就语言规则而言,两个同步点之间发生的一切都是“同时”的。

可以在 N4140 的 § 1.10 [intro.multithreaded] 中找到关于此的最终规则。 ,C++14 标准的最终草案。但是那里使用的语言可能很难破译。

在 Bjarne Stroustrup 的 The C++ Programming Language(第 4 版)的第 41.2.4 节中可以找到更通俗的解释。

Two threads have a data race if both can access a memory location simultaneously and at least one of their accesses is a write. Note that defining “simultaneously” precisely is not trivial. If two threads have a data race, no language guarantees hold: the behavior is undefined.

就我而言,我认为第一句中的“can”是假的,不应该出现,但我是按原样引用这本书。

保护相互访问的经典方法是使用互斥锁和锁。从 C++11 开始(而且只有从 C++11 开始,C++ 才有并发的定义),标准库提供了 std::mutex std::lock_guard (均在 <mutex> header 中定义)用于此目的。

但是,如果您有像整数这样的简单类型,那么使用锁就有点过分了。现代硬件支持对此类简单类型的原子 操作。标准库提供了 std::atomic 为此的类模板(在 <atomic> header 中定义)。您可以在任何普通可复制类型上使用它。

这是一个相当无用的例子,我们有两个线程执行函数 writerreader分别。 writer有一个伪随机数生成器并定期要求它生成一个新的随机整数,它以原子方式存储在全局变量 value 中。 . reader定期加载 value 的值原子地推进它自己的伪随机数生成器,直到它 catch 。第二个全局原子变量 done主线程使用它向两个线程发出停止信号。请注意,我已将您的赫兹替换为千赫兹,这样等待程序执行就不会那么无聊了。

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


namespace /* anonymous */
{

std::atomic<bool> done {};
std::atomic<int> value {};

void
writer(const std::chrono::microseconds period)
{
auto rndeng = std::default_random_engine {};
auto rnddst = std::uniform_int_distribution<int> {};
while (!done.load())
{
const auto next = rnddst(rndeng);
value.store(next);
std::this_thread::sleep_for(period);
}
}

void
reader(const std::chrono::microseconds period)
{
auto rndeng = std::default_random_engine {};
auto rnddst = std::uniform_int_distribution<int> {};
auto last = 0;
while (!done.load())
{
const auto next = value.load();
while (last != next)
last = rnddst(rndeng);
std::this_thread::sleep_for(period);
}
}

}


int
main()
{
using namespace std::chrono_literals;
std::thread writer_thread {writer, 100us}; // 10 kHz
std::thread reader_thread {reader, 10us}; // 100 kHz
std::this_thread::sleep_for(3s);
done.store(true);
writer_thread.join();
reader_thread.join();
}

如果您有现代 GCC 或 Clang,您可以(并且可能应该)使用 -fsanitize=thread 编译您的调试版本。转变。如果您运行这样编译的二进制文件并执行数据竞争,编译器添加的特殊检测将输出一条有用的错误消息。尝试更换 std::atomic<int> value在上面的程序中有一个普通的 int value并查看该工具将报告什么。

如果您还没有 C++14,则不能使用文字后缀,而必须拼出 std::chrono::microseconds {10}等等。

关于c++ - 从另一个对象指向线程对象 : dangerous?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33058474/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com