【问题标题】:Why do I get Access Violation in mutithreading aplication in C while I exit the main() before the threads finish?为什么在线程完成之前退出 main() 时,在 C 中的多线程应用程序中会出现访问冲突?
【发布时间】:2016-09-13 07:03:24
【问题描述】:

我有一个程序,我创建了 4 个线程,但只等待第一个线程[0]。 线程只是打印一些内容。但是当我执行以下程序时,我会得到访问冲突 有时

#include<Windows.h>
#include <stdio.h>
#include<tchar.h>

#define KEYLEN 8
#define DATALEN 56
typedef struct _RECORD{
    CHAR key[KEYLEN];
    TCHAR data[DATALEN];        
}RECORD;
#define RECSIZE sizeof(RECORD)
typedef RECORD *LPRECORD;

typedef struct _THREADARG{
    DWORD iTh;
    LPRECORD lowRecord;         // pointer to Low record 
    LPRECORD highRecord;
} THREADARG, *PTHREADARG;

static int KeyCompare(LPCTSTR, LPCTSTR);
static DWORD WINAPI SortThread(PTHREADARG pThArg);
static DWORD nRec;  // Total Number of records to be sorted
static HANDLE *pThreadHandle;


DWORD Options (int argc, LPCTSTR argv [], LPCTSTR OptStr, ...);

int _tmain(int argc, LPTSTR argv[]){
HANDLE hFile, mHandle;
LPRECORD pRecords = NULL;
DWORD lowRecordNum, nRecTh,numFiles, iTh;
LARGE_INTEGER fileSize;
BOOL noPrint;
int iFF, iNP;
PTHREADARG threadArg;
LPTSTR stringEnd;

iNP = 1;
iFF = iNP + 1;
numFiles = _ttoi(argv[iNP]);

if (argc <= iFF)
    _tprintf (_T ("Usage: sortMT [options] nTh files."));

/* Open the file and map it */
hFile = CreateFile (argv[iFF], GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
    _tprintf (_T ("Failure to open input file."));

if (!SetFilePointer(hFile, 2, 0, FILE_END) || !SetEndOfFile(hFile))
    _tprintf (_T ("Failure position extend input file."));

mHandle = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (NULL == mHandle)
    _tprintf (_T ("Failure to create mapping handle on input file."));

/* Get the file size. */
if (!GetFileSizeEx (hFile, &fileSize))
    _tprintf (_T ("Error getting file size."));

nRec = (DWORD)fileSize.QuadPart / RECSIZE;  
nRecTh = nRec / numFiles;   
threadArg = malloc (numFiles * sizeof (THREADARG)); /* Array of thread args. */ 
pThreadHandle = malloc (numFiles * sizeof (HANDLE));

/* Map the entire file */
pRecords = MapViewOfFile(mHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0); 
if (NULL == pRecords)
    _tprintf (_T ("Failure to map input file."));
CloseHandle (mHandle);

/* Create the sorting threads. */
lowRecordNum = 0;
for (iTh = 0; iTh < numFiles; iTh++) {
    threadArg[iTh].iTh = iTh;
    threadArg[iTh].lowRecord = pRecords + lowRecordNum;
    threadArg[iTh].highRecord = pRecords + (lowRecordNum + nRecTh);
    lowRecordNum += nRecTh;
    pThreadHandle[iTh] = (HANDLE)_beginthreadex (
        NULL, 0, SortThread, &threadArg[iTh], CREATE_SUSPENDED, NULL);
}

/* Resume all the initially suspened threads. */

for (iTh = 0; iTh < numFiles; iTh++)
    ResumeThread (pThreadHandle[iTh]);


/* Wait for the sort-merge threads to complete. */

WaitForSingleObject (pThreadHandle[0], INFINITE);   
for (iTh = 0; iTh < numFiles; iTh++);
    CloseHandle (pThreadHandle[iTh]);

//Sleep(3);  // Un comment it and see no error.


UnmapViewOfFile(pRecords);
// Restore the file length
/* SetFilePointer is convenient as it's a short addition from the file end */
if (!SetFilePointer(hFile, -2, 0, FILE_END) || !SetEndOfFile(hFile))
    _tprintf("Failure restore input file lenght.");

CloseHandle(hFile);
free (threadArg); free (pThreadHandle);
return 0;
}


DWORD WINAPI SortThread(PTHREADARG pThArg){

DWORD groupSize = 2, myNumber, twoToI = 1;
        /* twoToI = 2^i, where i is the merge step number. */
DWORD_PTR numbersInGroup;
LPRECORD first;

myNumber = pThArg->iTh;
first = pThArg->lowRecord; 
numbersInGroup = (DWORD)(pThArg->highRecord - first); 

printf(" %d : %s \n",myNumber,  pThArg->lowRecord );

return 0;
}

文件内容结构:

02d2d159. Record Number: 00000000.abcdefghijklmnopqrstuvwxyz X
f362711e. Record Number: 00000001.abcdefghijklmnopqrstuvwxyz X
ba957dff. Record Number: 00000002.abcdefghijklmnopqrstuvwxyz X

但是如果我在创建线程之后给一个 Sleep(N); 就没有问题了。! 所以我理解 main() 线程在子线程之前退出。但是当 main() 退出时,整个进程应该终止。不是吗? 那么访问冲突怎么可能呢?

为什么我访问冲突?

【问题讨论】:

  • 你能把你的例子缩小到它仍然发生的地方并且没有任何不必要的东西吗?但可能发生的情况是,在内部清理内存时,您的线程仍在此全局内存上运行和操作。
  • 在调用任何堆内存分配函数(malloc、calloc、realloc)时,始终检查 (!=NULL) 返回值以确保操作成功。
  • 为了便于阅读和理解:1) 遵循公理:每行只有一个语句,并且(最多)每个语句一个变量声明。
  • 最好将结构定义与使用该结构的typedef 定义分开

标签: c multithreading pointers


【解决方案1】:

但是当main()退出时,整个进程应该终止。

最终是的,但是在从main 返回和实际进程终止之间实际上可能有很多代码在运行、破坏进程映像等。

因此,当你...

free (threadArg); free (pThreadHandle);

...还有一个或多个线程尚未完成,将...

printf(" %d : %s \n",myNumber,  pThArg->lowRecord );

...访问例如他们的线程参数pThArg(现已删除)你已经注册了麻烦。

请注意,这只是一个示例。从main 返回后,可能还有更多(内部)共享数据被释放,但仍被线程使用(例如,它们的堆栈,线程句柄......)。

道德:在释放该资源之前等待所有个使用资源的线程终止。


另外:pThArg-&gt;lowRecord 不是char * 所期望的char *,因此你也有未定义的行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多