2015-04-28 2 views
1

Я хотел бы создать программу, которая контролирует некоторые процессы. Для этого я создал структуру, содержащую процессы для мониторинга, другую структуру, которая содержит, какие процессы все еще работают, и поток, который выполняет эту работу. В потоке (struct, который содержит запущенные процессы) ProcArrayDisplay, будет свободным() 'd, чтобы удалить структуру, а затем malloc()' d и снова заполнить. Я не уверен, если это лучший способ. И вот моя проблема. Если работает 2 или более процесса, я всегда получаю Access vioalation.Как правильно перенаправить бесплатную() 'структуру d?

Я думаю, это связано с тем, что счетчик структуры является глобальной переменной, а когда Thread изменяет его, что-то идет не так. Я пытался использовать, Critical sections и InterLockedIncrement/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; 
} 
+0

'перераспределить свободный() 'd struct' ... ждать, вы ожидаете получить обратно' свободные() 'd данные? –

+0

@SouravGhosh: Нет, я не хочу возвращать данные free() 'd. Я освобождаю структуру, поэтому она будет пустой, а затем снова заполняет ее malloc. Извините, если я не могу объяснить лучше, чего я хочу. Мой английский не самый лучший. – kampi

+1

Не можете ли вы просто «ноль» ('memset') вашей структуры? Вы должны освободить его только тогда, когда знаете, что вам больше не нужно. Обратите внимание, что 'free' не пустует вашу структуру: он выделяет выделенное пространство как доступное для другого выделения. Также сузите соответствующие части кода. – Coconop

ответ

1

Если структура доступна на другом потоке и использовать повторно несколько раз, я хотел бы предложить:

  • выделить его один раз
  • защитить его с 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]; 
+0

Если я всегда использую memset, тогда память все еще остается выделенной, не так ли? Эта структура может расти и может сокращаться в зависимости от того, сколько процессов все еще выполняется, от процессов, которые я хочу контролировать. Если я использую memset, то только данные получат NULLd, а счетчик должен быть установлен на 0. После этого мне нужно добавить, элементы снова, которые все еще запущены, поэтому счетчик не будет удерживать Count выделенного элементов, и поэтому их невозможно освободить. Или я ошибаюсь? – kampi

+0

«Память остается выделенной»: справа. Если его структура должна расти/сокращаться, то memset не достаточно: вам нужно перераспределить. Память, выделенная через malloc, будет правильно освобождена. Если структура содержит вложенные выделенные элементы, они должны быть освобождены до memset, если они не упоминаются в другом месте, чтобы избежать утечки памяти. – Coconop

+0

Извините, но я до сих пор не понимаю ее полностью. Если я просто memset структуры и добавить его снова, то отладчик показывает, что существует много памяти, которая не была бесплатной() d. Функция 'AddItemsToDisplayArray' добавляет элемент в массив, а функция' FreeStructDisplay' освобождает его. Я называю эти две функции в цикле. И при выходе из программы я вызываю 'FreeStruct()', который вызывает 'FreeStructDisplay()', а затем 'free (ProcArrayDisplay);' – kampi