gpt4 book ai didi

c++ - 导致非原子撕裂

转载 作者:可可西里 更新时间:2023-11-01 10:22:06 25 4
gpt4 key购买 nike

您好,我想要一个 int 和 float 示例,它们会导致使用非原子值写入时出现撕裂。我似乎无法重现这一点。这似乎是非常罕见的事情,或者我做错了什么。

这是我从未打印过的测试代码。有什么问题吗?

#include <windows.h>
#include <tchar.h>
#include <strsafe.h>

#define MAX_THREADS 64
#define BUF_SIZE 255

DWORD WINAPI MyThreadFunction( LPVOID lpParam );
void ErrorHandler(LPTSTR lpszFunction);

// Sample custom data structure for threads to use.
// This is passed by void pointer so it can be any data type
// that can be passed using a single void pointer (LPVOID).
typedef struct MyData {
int val1;
int val2;
} MYDATA, *PMYDATA;


int _tmain()
{
DWORD dwThreadIdArray[MAX_THREADS];
HANDLE hThreadArray[MAX_THREADS];

// Create MAX_THREADS worker threads.

for( int i=0; i<MAX_THREADS; i++ )
{
// Allocate memory for thread data.
// Create the thread to begin execution on its own.

hThreadArray[i] = CreateThread(
NULL, // default security attributes
0, // use default stack size
MyThreadFunction, // thread function name
NULL, // argument to thread function
0, // use default creation flags
&dwThreadIdArray[i]); // returns the thread identifier


// Check the return value for success.
// If CreateThread fails, terminate execution.
// This will automatically clean up threads and memory.

if (hThreadArray[i] == NULL)
{
ErrorHandler(TEXT("CreateThread"));
ExitProcess(3);
}
} // End of main thread creation loop.

// Wait until all threads have terminated.

WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);

// Close all thread handles and free memory allocations.

for(int i=0; i<MAX_THREADS; i++)
{
CloseHandle(hThreadArray[i]);
}

return 0;
}

#pragma pack(push, 1)
struct Test
{
char x1;
char x1;
char x3;
int test;
char x4;
char x5;
};

Test* t = new Test(); //This is test code don't care about allocation or that it is a global.
#pragma pack(pop)

DWORD WINAPI MyThreadFunction( LPVOID lpParam )
{
HANDLE hStdout;

TCHAR msgBuf[BUF_SIZE];
size_t cchStringSize;
DWORD dwChars;

// Make sure there is a console to receive output results.

hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
if( hStdout == INVALID_HANDLE_VALUE )
return 1;

static int thread = 0;
StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Starting thread, %d\n"), ++thread);
StringCchLength(msgBuf, BUF_SIZE, &cchStringSize);
WriteConsole(hStdout, msgBuf, (DWORD)cchStringSize, &dwChars, NULL);

t->test = 1;

for (int i=0; i<1000000000;++i)
{
t->test = 1;
t->test = 10000;
t->test = 10000000;

int result = t->test;

if(result != 1 && result != 10000 && result != 10000000)
{
StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Tearing occured = %d\n"), result);
StringCchLength(msgBuf, BUF_SIZE, &cchStringSize);
WriteConsole(hStdout, msgBuf, (DWORD)cchStringSize, &dwChars, NULL);
}
}


return 0;
}



void ErrorHandler(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code.

LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );

// Display the error message.

lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR) lpDisplayBuf, TEXT("Error"), MB_OK);

// Free error-handling buffer allocations.

LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}

最佳答案

当使用 Visual Studio 2013 编译时,我可以使用此测试代码触发读取/写入中断,这会强制竞争的 uint32_t 跨越缓存行边界(似乎只发生在发布版本中):

#include <algorithm>
#include <atomic>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>

using namespace std;

atomic<bool> gDone = false;

vector<uint32_t> vals = {0x11111111, 0x22222222, 0x33333333, 0x44444444, };

mutex ioMutex;

void writeVal(volatile uint32_t* pVal, int tid) {
while (!gDone) {
*pVal = vals[tid];
const auto currentVal = *pVal;
auto findIt = find(begin(vals), end(vals), currentVal);
if (findIt == end(vals)) {
unique_lock<mutex> ul(ioMutex);
cout << "Detected torn read/write! pVal = 0x" << setbase(16) << setw(8) << setfill('0')
<< reinterpret_cast<uintptr_t>(pVal) << " currentVal = 0x" << currentVal << endl;
gDone = true;
}
}
}

int main() {
vector<char> memVec(16 * 1024);
char* first = &memVec[0];
const auto cacheLineSize = 64;
char* crossesCacheLine =
reinterpret_cast<char*>((reinterpret_cast<uintptr_t>(first + cacheLineSize) & ~(cacheLineSize - 1)) - 2);
uint32_t* tearableUint32 = reinterpret_cast<uint32_t*>(crossesCacheLine);
vector<thread> threads(vals.size());
for (int i = 0; i != threads.size(); ++i) {
threads[i] = thread([=] { writeVal(tearableUint32, i); });
}
for (auto& t : threads) {
t.join();
}
}

输出:

Detected torn read/write! pVal = 0x004bc43e currentVal = 0x11112222

关于c++ - 导致非原子撕裂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25794803/

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