c语言 - 如何再次正确地重新分配一个自由()结构?



我想创建一个程序,用于监视一些进程。为此,我创建了一个结构,其中包含要监视的进程,另一个结构包含仍在运行的进程,以及一个线程来完成工作。在线程中,(包含正在运行的进程的结构)ProcArrayDisplay将是free()'d,以清空结构,然后malloc()'d,并再次填充。我不确定这是否是最好的方式。这就是我的问题。如果有两个或多个进程在运行,我总是得到Access vioalation

我认为这是因为,结构的Counter是一个全局变量,当Thread修改它时,就会出现问题。我试着使用Critical sectionsInterLockedIncrement/InterLockedDecrement,但我仍然得到了Access violation

那么,我做错了什么,我应该如何做对呢?

提前感谢!

我的代码:

#include <Windows.h>
#include <Conio.h>
#include <process.h>
#include <TlHelp32.h>
struct ProcToQuery
{
wchar_t * ProcessName;
wchar_t * DisplayName;
};
struct ProcToQuery **ProcArrayQuery = NULL;
int ProcArrayCountQuery = 0;
struct ProcToDisplay
{
wchar_t * ProcessName;
wchar_t * DisplayName;
};
struct ProcToDisplay **ProcArrayDisplay = NULL;
volatile long ProcArrayCountDisplay = 0;
typedef struct
{
BOOL bKill;
}PARAMS, *PPARAMS;
void AddItemsToQueryArray( wchar_t * ProcessName, wchar_t * DisplayName );
void AddItemsToDisplayArray( wchar_t * ProcessName, wchar_t * DisplayName );
void FreeStruct();
void FreeStructDisplay();
BOOL IsProcessRunning( wchar_t * ProcessName, wchar_t * DisplayName );
unsigned __stdcall Thread( void *ArgList );
int _tmain(int argc, _TCHAR* argv[])
{
AddItemsToQueryArray( L"notepad.exe", L"Notepad" );
AddItemsToQueryArray( L"calc.exe", L"Calculator" );
PARAMS params;
params.bKill = FALSE;
unsigned int ThreadId;
for ( int i = 0; i < ProcArrayCountQuery; i++ )
{
if ( !IsProcessRunning( ProcArrayQuery[ i ]->ProcessName, ProcArrayQuery[ i ]->DisplayName ) )
{
// IsProcessRunning failed
return 1;
}
}
if ( ProcArrayCountDisplay == 0 )
{
printf( "nNone of the processes are running" );
FreeStruct();
return 0;
}
HANDLE hThread = ( HANDLE )_beginthreadex( NULL, 0, Thread, &params, 0, &ThreadId );
// do some work
Sleep(20000);
params.bKill = TRUE;
DWORD dwExitCode;
DWORD dwRet = WaitForSingleObject( hThread, 2000 );
if ( dwRet == WAIT_OBJECT_0 )
{
// the thread has terminated 
GetExitCodeThread( hThread, &dwExitCode );
printf( "nThread finished ExitCode = %d", dwExitCode );
}
else if ( dwRet == WAIT_TIMEOUT )
{
// thread still active
GetExitCodeThread( hThread, &dwExitCode );
printf( "nThread still active ExitCode = %d", dwExitCode );
}
else if ( dwRet == WAIT_FAILED )
{
printf( "nWaitForSingleObject failed = %d", GetLastError() );
}
CloseHandle( hThread );
_getch();
return 0;
}
void AddItemsToQueryArray( wchar_t * ProcessName, wchar_t * DisplayName )
{
struct ProcToQuery **tmp = ( struct ProcToQuery ** )realloc( ProcArrayQuery, ( ProcArrayCountQuery + 1 ) * sizeof( struct ProcToQuery * ) );
if ( tmp == NULL )
{
return;
}
ProcArrayQuery = tmp;
ProcArrayQuery[ ProcArrayCountQuery ] = ( struct ProcToQuery * )malloc( sizeof **ProcArrayQuery );
if ( ProcArrayQuery[ ProcArrayCountQuery ] == NULL )
{
return;
}
ProcArrayQuery[ ProcArrayCountQuery ]->ProcessName = _wcsdup( ProcessName );
ProcArrayQuery[ ProcArrayCountQuery ]->DisplayName = _wcsdup( DisplayName );
ProcArrayCountQuery++;
}//AddItemsToQueryArray
void AddItemsToDisplayArray( wchar_t * ProcessName, wchar_t * DisplayName )
{
struct ProcToDisplay **tmp = ( struct ProcToDisplay ** )realloc( ProcArrayDisplay, ( ProcArrayCountDisplay + 1 ) * sizeof( struct ProcToDisplay * ) );
if ( tmp == NULL )
{
return;
}
ProcArrayDisplay = tmp;
ProcArrayDisplay[ ProcArrayCountDisplay ] = ( struct ProcToDisplay * )malloc( sizeof **ProcArrayDisplay );
if ( ProcArrayDisplay[ ProcArrayCountDisplay ] == NULL )
{
return;
}
ProcArrayDisplay[ ProcArrayCountDisplay ]->ProcessName = _wcsdup( ProcessName );
ProcArrayDisplay[ ProcArrayCountDisplay ]->DisplayName = _wcsdup( DisplayName );
ProcArrayCountDisplay++;
}//AddItemsToDisplayArray
void FreeStruct()
{
for ( int i = 0; i < ProcArrayCountQuery; i++ )
{
if ( ProcArrayQuery[ i ]->DisplayName ) free( ProcArrayQuery[ i ]->DisplayName );
if ( ProcArrayQuery[ i ]->ProcessName ) free( ProcArrayQuery[ i ]->ProcessName );
if ( ProcArrayQuery[ i ] ) free( ProcArrayQuery[ i ] );
}
free( ProcArrayQuery );
FreeStructDisplay();
free( ProcArrayDisplay );
}//FreeStruct
void FreeStructDisplay()
{
for ( int i = 0; i < ProcArrayCountDisplay; i++ )
{
if ( ProcArrayDisplay[ i ]->ProcessName ) free( ProcArrayDisplay[ i ]->ProcessName );
if ( ProcArrayDisplay[ i ]->DisplayName ) free( ProcArrayDisplay[ i ]->DisplayName );
if ( ProcArrayDisplay[ i ] ) free( ProcArrayDisplay[ i ] );
ProcArrayCountDisplay--;
}
}
BOOL IsProcessRunning( wchar_t * ProcessName, wchar_t * DisplayName )
{
PROCESSENTRY32 process;
HANDLE snapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if ( snapshot == INVALID_HANDLE_VALUE )
{
return FALSE;
}
ZeroMemory( &process, sizeof( process ) );
process.dwSize = sizeof( process );
if ( Process32First( snapshot, &process ) )
{
do
{
if ( ( _wcsicmp( process.szExeFile, ProcessName ) == 0 ) )
{
printf("n%ls is running", ProcessName );
AddItemsToDisplayArray( ProcessName, DisplayName );
}
} while ( Process32Next( snapshot, &process ) == TRUE );
}
else
{
// Process32First failed
CloseHandle( snapshot );
return FALSE;
}
CloseHandle( snapshot );
return TRUE;
}
unsigned __stdcall Thread( void *ArgList )
{
PPARAMS pparams;
pparams = ( PPARAMS )ArgList;
while ( !pparams->bKill )
{
// Request ownership of the critical section.
//      EnterCriticalSection( &CriticalSection );
FreeStructDisplay();
printf("n----------------------------------------------------");
for ( int i = 0; i < ProcArrayCountQuery; i++ )
{
if ( !IsProcessRunning( ProcArrayQuery[ i ]->ProcessName, ProcArrayQuery[ i ]->DisplayName ) )
{
// IsProcessRunning failed
return 1;
}
}
if ( ProcArrayCountDisplay == 0 )
{
// no package to display
break;
}
// Release ownership of the critical section.
//  LeaveCriticalSection( &CriticalSection );
Sleep( 1000 );
}
_endthread();
return 0;
}

如果不同线程可以访问该结构并多次重复使用,我建议:

  • 分配一次
  • mutex保护它:用lock/unlock对此结构进行环绕操作
  • 使用memset清空结构,即将所有字段设置为0
  • 一旦你知道它将不再使用,就将其释放

据我所知,你想"清空"你的结构,所以memset似乎是一个很好的解决方案(尽管你可以在需要时覆盖字段):它会解决访问冲突问题,因为你的结构仍然存在(但在使用它之前别忘了检查字段值)
正如评论中所说,free并没有"清空"您的结构:它只是将您通过malloc保留的内存标记为再次可用。在其他内容写入之前,内容将保持不变。

[EDIT]
糟糕的是,我错过了您使用wcsdup的事实,它分配了一个新字符串,该字符串将为free
如果你事先知道你正在操作的字符串的最大大小,这是可以避免的:

struct ProcToQuery
{
wchar_t ProcessName[MAX_STRING_SIZE];
wchar_t DisplayName[MAX_STRING_SIZE];
};

然后您可以使用wcscpy而不是wcsdup,并且您不需要新的分配。ProcArrayQuery:也是如此

struct ProcToQuery * ProcArrayQuery[MAX_QUERY];

最新更新