我在Windows中玩Threading并编写了这个例子,它应该添加128Mb阵列的所有位置。我创建x线程来计算总和,所以我将数组除以x peaces并让每个线程计算其中一个和平。这一切都很好,直到我尝试创建超过64个线程。例如,如果我创建65个线程,我的add函数中会出现访问冲突。我的猜测是它是一个超出界限的数组,我只是无法理解为什么64个线程后我得到这个错误。
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#define MAX_ARRAY_SIZE 128 * 1024 * 1024
#define MAX_THREADS_BUFFER 512
DWORD dwSampleData[MAX_ARRAY_SIZE];
DWORD dwTotal;
DWORD WINAPI DoWork(LPVOID lpParam);
void ErrorHandler(LPTSTR lpszFunction);
VOID InitializedwSampleData();
VOID CreateThreadsAndDoWork(DWORD MaxThreads, DWORD dwPrintIntermediateResults);
typedef struct _THREAD_ARGS{
DWORD * pdwSampleData;
DWORD dwOffset;
DWORD dwSize;
DWORD dwPrintIntermediateResults;
}THREAD_ARGS, *PTHREAD_ARGS;
DWORD _tmain()
{
InitializedwSampleData();
CreateThreadsAndDoWork(1, FALSE);
CreateThreadsAndDoWork(2, FALSE);
CreateThreadsAndDoWork(4, FALSE);
CreateThreadsAndDoWork(8, FALSE);
CreateThreadsAndDoWork(16, FALSE);
CreateThreadsAndDoWork(32, FALSE);
CreateThreadsAndDoWork(64, FALSE);
CreateThreadsAndDoWork(128, FALSE); // <----------- More than 64 threads
printf("Press any key to finish");
getchar();
return 0;
}
VOID InitializedwSampleData(){
DWORD i;
for (i = 0; i < MAX_ARRAY_SIZE; i++){
dwSampleData[i] = 1;
}
}
VOID CreateThreadsAndDoWork(DWORD MaxThreads, DWORD dwPrintIntermediateResults){
PTHREAD_ARGS pDataArray[MAX_THREADS_BUFFER];
DWORD dwThreadIdArray[MAX_THREADS_BUFFER];
HANDLE hThreadArray[MAX_THREADS_BUFFER];
DWORD BeginTickCount;
// Reset dwTotal;
dwTotal = 0;
// Get Initial Tick Count
BeginTickCount = GetTickCount();
// Create MAX_THREADS worker threads.
for (DWORD i = 0; i < MaxThreads; i++)
{
// Allocate memory for thread data.
pDataArray[i] = (PTHREAD_ARGS)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(THREAD_ARGS));
if (pDataArray[i] == NULL)
{
// If the array allocation fails, the system is out of memory
// so there is no point in trying to print an error message.
// Just terminate execution.
ExitProcess(2);
}
// Generate data for each thread to work with.
pDataArray[i]->dwOffset = i * (MAX_ARRAY_SIZE / MaxThreads);
pDataArray[i]->dwSize = MAX_ARRAY_SIZE / MaxThreads;
pDataArray[i]->pdwSampleData = dwSampleData;
pDataArray[i]->dwPrintIntermediateResults = dwPrintIntermediateResults;
// Create the thread to begin execution on its own.
hThreadArray[i] = CreateThread(
NULL, // default security attributes
0, // use default stack size
DoWork, // thread function name
pDataArray[i], // 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(MaxThreads, hThreadArray, TRUE, INFINITE);
// Close all thread handles and free memory allocations.
for (DWORD i = 0; i < MaxThreads; i++)
{
CloseHandle(hThreadArray[i]);
if (pDataArray[i] != NULL)
{
HeapFree(GetProcessHeap(), 0, pDataArray[i]);
pDataArray[i] = NULL; // Ensure address is not reused.
}
}
// Print Results
_tprintf(TEXT("Computation task with %d thread(s): Added to %d in %d mills\n"), MaxThreads, dwTotal, GetTickCount() - BeginTickCount);
}
DWORD WINAPI DoWork(LPVOID lpParam)
{
DWORD i;
DWORD sum = 0;
for (i = ((PTHREAD_ARGS)lpParam)->dwOffset; i < ((PTHREAD_ARGS)lpParam)->dwSize + ((PTHREAD_ARGS)lpParam)->dwOffset; i++){
sum += ((PTHREAD_ARGS)lpParam)->pdwSampleData[i]; // <------------ ACCESS VIOLATION ERROR
}
dwTotal += sum;
if (((PTHREAD_ARGS)lpParam)->dwPrintIntermediateResults){
_tprintf(TEXT("\nSUM = %d\n"), sum);
}
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);
}
答案 0 :(得分:4)
WaitForMultipleObjects
对可以等待的线程数有限制。该限制为MAXIMUM_WAIT_OBJECTS
,其值为64.
这意味着当你调用WaitForMultipleObjects
传递128个句柄时,它会立即返回错误,你只是忽略它。要完全清楚,WaitForMultipleObjects
在线程完成之前返回。然后,您释放堆内存,导致仍在运行的线程在尝试访问现已释放的内存时失败。
要学习的主要课程始终是检查Win32 API函数的返回值。如果您检查了WaitForMultipleObjects
返回的值,您就会发现问题。
要解决此问题,您需要在循环中重复调用WaitForMultipleObjects
。等待第一个MAXIMUM_WAIT_OBJECTS
个线程。然后是下一个WaitForMultipleObjects
个线程。等等,直到没有其他等待的时间。