在Microsoft Visual C ++中,我可以通过启动具有一个void *
参数的函数来调用CreateThread()来创建线程。我将指向结构的指针作为该参数传递,我看到很多其他人也这样做了。
我的问题是,如果我传递一个指向我的结构的指针,我如何知道在调用CreateThread()之前结构成员是否已实际写入内存?有没有保证他们不会被缓存?例如:
struct bigapple { string color; int count; } apple;
apple.count = 1;
apple.color = "red";
hThread = CreateThread( NULL, 0, myfunction, &apple, 0, NULL );
DWORD WINAPI myfunction( void *param )
{
struct bigapple *myapple = (struct bigapple *)param;
// how do I know that apple's struct was actually written to memory before CreateThread?
cout << "Apple count: " << myapple->count << endl;
}
今天下午,在我阅读的时候,我在这个网站上看到了很多Windows代码,而其他人则传递了一些不易变为线程的数据,并且似乎没有任何内存障碍或其他任何内容。我知道C ++或者至少旧的版本不是“线程感知”所以我想知道是否还有其他原因。我的猜测是编译器看到我在调用CreateThread()时传递了指针&amp; apple,因此它知道在调用之前写出apple
的成员。
由于
答案 0 :(得分:5)
没有。相关的Win32线程函数都会处理必要的内存障碍。 CreateThread
之前的所有写入对新线程都是可见的。显然,在调用CreateThread
之前,新创建的线程中的读取不能重新排序。
volatile
不会在编译器上添加任何额外的有用约束,只会减慢代码速度。实际上,与创建新线程的成本相比,thiw并不明显。
答案 1 :(得分:2)
不,它不应该是volatile
。与此同时,您指的是有效问题。英特尔/ ARM /等论文中描述了缓存的详细操作。
尽管如此,您可以放心地假设数据将被写入。否则会有太多事情被打破。几十年的经验告诉我们是这样的。
如果线程调度程序将在同一核心上启动线程,则缓存的状态将正常,否则,如果不是,则内核将刷新缓存。否则,什么都行不通。
永远不要使用volatile
进行线程之间的交互。它是关于如何仅处理线程内数据的指令(使用寄存器副本或总是重读等)。
答案 2 :(得分:1)
首先,我认为优化器不能以牺牲正确性为代价来改变顺序。 CreateThread()是一个函数,函数调用的参数binidng在调用之前发生。
其次, volatile 对你想要的目的不是很有帮助。 Check out this article
答案 3 :(得分:0)
你正在努力解决一个非问题,并且正在创造至少另外两个......
new
创建它们以便它们一直存在直到调用delete
(或直到进程终止:良好的内存泄漏!)< / LI>
CreateThread
形式的语言,这些语言也有自己的库,也与线程接口。 C运行时具有_beginthreadex
。它调用CreateThread
并执行您将错过的C ++库的其他初始化任务。如果没有这些初始化,某些C(和C ++)库函数可能无法正常工作,这也是在终止时正确释放运行时资源所必需的。取消CreateThread
就像在malloc
用于清理的上下文中使用delete
一样。正确的主线程应该是
// create the data
// create the other thread
// // perform othe task
// wait for the oter thread to terminate
// destroy the data
win32 API文档没有明确说明每个HANDLE
是 waitable ,并在释放关联资源时发出信号。
要等待其他线程终止,您的主线程将只需要调用
WaitForSingleObject(hthread,INFINITE);
所以主线程会更恰当:
{
data* pdata = new data;
HANDLE hthread = (HANDLE)_beginthreadex(0,0,yourprocedure, pdata,0,0);
WaitForSingleObject(htread,INFINITE);
delete pdata;
}
甚至
{
data d;
HANDLE hthread = (HANDLE)_beginthreadex(0,0,yourprocedure, &d,0,0);
WaitForSingleObject(htread,INFINITE);
}
答案 4 :(得分:0)
我认为这个问题在另一个背景下是有效的。 正如其他人已指出使用结构并且内容是安全的(尽管应该通过同步访问数据)。
但是我认为如果你有一个可以在线程外部改变的原子变量(或指向一个的指针),这个问题是有效的。在这种情况下,我的意见是在这种情况下应该使用volatile。
修改强> 我认为维基页面上的示例是一个很好的解释http://en.wikipedia.org/wiki/Volatile_variable