Why does multi threading mess up my file watcher? - c++

I am trying to make a file watcher that watches multiple directories simultaneously and i found a function that watches one directory and it works well. So I tried to create multiple threads with the same function and just give them the different paths of the directories as parameters. And it still works, but not perfectly. It does provide me with the first change in one directory, but then it gets stuck for that one and in the other directories the changes i make are printed as if they wore made in the first directory. I think the threads are getting messed up and I don`t know why. Here is the function
void watch_directory(LPCSTR path, int i)
{
char buf[2048];
DWORD nRet;
BOOL result = TRUE;
char filename[MAX_PATH];
DirInfo[0].hDir = CreateFile(path, GENERIC_READ | FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
if (DirInfo[0].hDir == INVALID_HANDLE_VALUE)
{
return; //cannot open folder
}
lstrcpy(DirInfo[0].lpszDirName, path);
OVERLAPPED PollingOverlap;
FILE_NOTIFY_INFORMATION* pNotify;
int offset;
PollingOverlap.OffsetHigh = 0;
PollingOverlap.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
while (result)
{
result = ReadDirectoryChangesW(
DirInfo[0].hDir,// handle to the directory to be watched
&buf,// pointer to the buffer to receive the read results
sizeof(buf),// length of lpBuffer
TRUE,// flag for monitoring directory or directory tree
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_SIZE,
&nRet,// number of bytes returned
&PollingOverlap,// pointer to structure needed for overlapped I/O
NULL);
WaitForSingleObject(PollingOverlap.hEvent, INFINITE);
offset = 0;
int rename = 0;
char oldName[260];
char newName[260];
do
{
pNotify = (FILE_NOTIFY_INFORMATION*)((char*)buf + offset);
strcpy(filename, "");
int filenamelen = WideCharToMultiByte(CP_ACP, 0, pNotify->FileName, pNotify->FileNameLength / 2, filename, sizeof(filename), NULL, NULL);
filename[pNotify->FileNameLength / 2] = '\0';
cout << pNotify->Action << i << filename << endl;
offset += pNotify->NextEntryOffset;
} while (pNotify->NextEntryOffset); //(offset != 0);
}
/*label:*/ CloseHandle(DirInfo[0].hDir);
}
And here is the way I create the threads:
vector <string> dirs;
vector <thread> threads;
dirs.push_back("F:\\Arhitecturi\\test0");
dirs.push_back("F:\\Arhitecturi\\test1");
for (int i = 0; i < dirs.size(); i++)
{
threads.push_back(thread(watch_directory, dirs[i].c_str(), i));
}
for (int i = 0; i < threads.size(); i++)
{
threads[i].join();
}

Related

Synchronize 2 processes using a mutex

I have 2 processes:
The first one creates a memory mapped region, a mutex and spawns
the second process. Then writes some pairs of numbers in the memory mapped region.
The second one opens the memory mapped region, opens the mutex and then reads the numbers written by the process 1.
I intended the first process to write a pair of numbers and the second one to immediately read it.
The process 2 seems to be starving.
What did I do wrong?
Process 1:
#include "stdafx.h"
#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
DWORD memSize = 400 * sizeof(DWORD);
HANDLE map_file = CreateFileMapping(NULL, NULL, PAGE_READWRITE, 0, memSize, TEXT("mem1"));
if (map_file == NULL)
{
_tprintf(_T("(Parent) File mapping is null\n"));
return 1;
}
char* map_ptr = (char *) MapViewOfFile(map_file, FILE_MAP_READ, 0, 0, 0);
if (map_ptr == NULL)
{
_tprintf(_T("(Parent) PTR is null \n"));
}
HANDLE hMutex = CreateMutex(NULL, TRUE, _T("mt"));
LPTSTR szCmdline = _tcsdup(TEXT("C:\\Users\\cristi\\source\\repos\\process_synchronization_reader\\Debug\\process_synchronization_reader.exe"));
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcess(NULL, szCmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
_tprintf(_T("Process created\n"));
}
_tprintf(_T("pare ca s-a creat"));
for (int i = 1; i <= 200; ++i)
{
WaitForSingleObject(hMutex, INFINITE);
_tprintf(_T("(Parent %d) writing from the parent\n"), i);
DWORD a, b;
CopyMemory((LPVOID) &a, map_ptr, sizeof(DWORD));
map_ptr += sizeof (DWORD);
CopyMemory((LPVOID) &b, map_ptr, sizeof(DWORD));
map_ptr += sizeof(DWORD);
ReleaseMutex(hMutex);
}
int n;
cin >> n;
CloseHandle(map_file);
return 0;
}
Process 2:
#include "stdafx.h"
#include <windows.h>
int main()
{
HANDLE map_file = OpenFileMapping(FILE_MAP_READ, FALSE, TEXT("mem1"));
if (map_file == NULL)
{
_tprintf(_T("(Child) File mapping is null\n"));
return 1;
}
char* map_ptr = (char *) MapViewOfFile(map_file, FILE_MAP_READ, 0, 0, 0);
if (map_ptr == NULL)
{
_tprintf(_T("(Child) PTR is null \n"));
}
_tprintf(_T("(CHILD) BEfore reading the first number\n"));
HANDLE hMutex = OpenMutex(SYNCHRONIZE, TRUE, _T("mt"));
for (int i = 1; i <= 200; i++)
{
WaitForSingleObject(hMutex, INFINITE);
DWORD a = i;
DWORD b = 2 * i;
CopyMemory((LPVOID) map_ptr, &a, sizeof(DWORD));
map_ptr += sizeof(DWORD);
CopyMemory((LPVOID) map_ptr, &b, sizeof(DWORD));
map_ptr += sizeof(DWORD);
_tprintf(_T("[================================================]\n"));
_tprintf(_T("( %d %d )\n"), a, b);
_tprintf(_T("[=================================================]\n"));
ReleaseMutex(hMutex);
}
return 0;
}
for got sequential write/read from shared memory we need 2 events (let name it Low and High).
first thread:
write data
signal Low event
wait on High event or break loop
goto 1
second thread:
wait on Low event
read data
break loop or signal High event
goto 1
unlike this solution mutex can not provide a sequence of reading / writing. mutex guarantee that until one thread will be access shared data (read or write) another thread will be not do this in concurrent. but this can not prevent several times in a row for write or read. really - insert messagebox in begin of process 2 - before he first time try acquire mutex - first process already many time acquire and release mutex. or if one thread will be suspended between release and wait for mutex - meanwhile another thread many time wait and release it. so code can look like:
struct SHARED_DATA
{
ULONG id;
ULONG nLoops;
BOOL bTask;
};
DWORD proc2(SHARED_DATA* p)
{
if (HANDLE hLowEvent = OpenEvent(SYNCHRONIZE, FALSE, L"LowEvent"))
{
if (HANDLE hHighEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, L"hHighEvent"))
{
ULONG id = GetCurrentThreadId();
for(;;)
{
if (WaitForSingleObject(hLowEvent, INFINITE) != WAIT_OBJECT_0)
{
break;
}
// ++ checking for sequence
if (p->id == id)
{
__debugbreak();// must never be
}
p->id = id;
// -- checking for sequence
if (!p->bTask)
{
// no more task
break;
}
// task done
p->bTask = FALSE;
// signal to #1
if (!SetEvent(hHighEvent))
{
break;
}
}
CloseHandle(hHighEvent);
}
CloseHandle(hLowEvent);
}
return 0;
}
DWORD proc1(SHARED_DATA* p)
{
if (HANDLE hLowEvent = CreateEvent(0, FALSE, FALSE, L"LowEvent"))
{
if (HANDLE hHighEvent = CreateEvent(0, FALSE, FALSE, L"hHighEvent"))
{
ULONG id = GetCurrentThreadId();
p->nLoops = 0x1000;
p->id = 0;
p->bTask = FALSE;
// exec proc2 here
goto __1;
do
{
if (WaitForSingleObject(hHighEvent, INFINITE) != WAIT_OBJECT_0)
{
break;
}
if (p->bTask)
{
__debugbreak();
}
// ++ checking for sequence
if (p->id == id)
{
__debugbreak();// must never be
}
__1:
p->id = id;
// -- checking for sequence
p->bTask = 0 < --p->nLoops;
// signal to #2
if (!SetEvent(hLowEvent))
{
break;
}
} while (p->nLoops);
CloseHandle(hHighEvent);
}
CloseHandle(hLowEvent);
}
return 0;
}
You create a mutex as initially owned (the second argument to CreateMutex is TRUE) and then you call a wait-function on it. So even after calling ReleaseMutex, it is still owned by a main thread of the first process.
Either change the argument to FALSE, or skip calling WaitForSingleObject for the first loop iteration.

Updating the PATH environment variable in Windows using C++

I am trying to launch a new process from my current process. I am using CreateProcess() to launch it. The issue is that I need to have certain directories in my PATH to successfully do so. Here is my current implementation but it doesn't work. What am I doing wrong?
// Environment variables
char *env = new char[2048];
char *ptr = env;
char temp[MAX_PATH] = "PATH=";
strcpy(ptr, strcat(temp, plugin_path));
ptr += strlen(ptr) + 1;
char temp2[MAX_PATH] = "PATH=";
strcpy(ptr, strcat(temp, lib_path));
ptr += strlen(ptr) + 1;
*ptr = '\0';
// Execute
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// error checking required
if(!CreateProcess(
NULL, // application name
command_path, // app.exe
NULL,
NULL,
TRUE,
0,
env, // environment
NULL,
&si,
&pi)) {
std::cout << GetLastError();
return 1;
}
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
std::cout << "Process Started!";
Please let me know if anything else is required.
EDIT: Somebody mentioned below that I need to be a little more specific. It doesn't work in the sense that the environment variables don't get passed. It fails because the library path is not in PATH. The createProcess does actually launch it though.
EDIT2: Here's the updated code. Same problem. Further, CreateProcess throws error 1087 which doesn't seem to exist in the docs.
// Environment variables
char env[2048];
char *ptr = env;
char *path_path = getenv("PATH");
// copy original path
memcpy(ptr, path_path, strlen(path_path));
ptr += strlen(ptr) + 1;
memcpy(ptr, ";", 1);
ptr++;
// copy plugin path
memcpy(ptr, plugin_path, strlen(plugin_path));
ptr += strlen(plugin_path) + 1;
memcpy(ptr, ";", 1);
ptr++;
// copy libpath
memcpy(ptr, lib_path, strlen(lib_path));
ptr += strlen(lib_path) + 1;
memcpy(ptr, ";", 1);
ptr++;
// double null terminated
memcpy(ptr, "\0\0", 2);
std::cout << "ENV : " << env << std::endl;
// error checking required
if(!CreateProcess(
NULL, // application name
command_path, // app.exe
NULL,
NULL,
TRUE,
0,
env, // environment
NULL,
&si,
&pi)) {
std::cout << GetLastError();
return 1;
}
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
std::cout << "Process Started!";
The PATH variable is a single variable. Different directories are listed in that variable, separated by semi-colons. But you've attempted to define the variable twice. That is the mistake.
The code should be something like this (assuming that you want to extend the existing path):
char *env = new char[2048]; // fingers crossed this is enough
strcpy(env, "PATH=");
strcat(env, getenv("PATH"));
strcat(env, ";");
strcat(env, plugin_path);
strcat(env, ";");
strcat(env, lib_path);
env[strlen(env)+1] = '\0';
Although this code (as is yours in the question) is simply begging for a buffer overrun.
It would be so much easier if you used C++ facilities to build your strings. For instance:
std::stringstream ss;
ss << "PATH=" << getenv("PATH");
ss << ";" << plugin_path;
ss << ";" << lib_path;
ss << '\0';
std::string env = ss.str();
Then pass env.c_str() to CreateProcess.
Not only does this make the code easier to read and verify, you know that you won't overrun any buffers.
I also note that you are passing an environment that has only one variable defined in it, namely PATH. It might be better if you started from the environment of the calling process, added the extra directories to PATH, and then passed that as the environment for the new process.
#include <iostream>
#include <windows.h>
#include <cstring>
#include "tchar.h"
void SetUserVariablePath(){
HKEY hkey;
long regOpenResult;
const char key_name[] = "Environment";
const char path[]="D:/custom_command"; //new_value path need to update
regOpenResult = RegOpenKeyEx(HKEY_CURRENT_USER,key_name, 0, KEY_ALL_ACCESS, &hkey);
LPCSTR stuff = "VVS_LOGGING_PATH"; //Variable Name
RegSetValueEx(hkey,stuff,0,REG_SZ,(BYTE*) path, strlen(path));
RegCloseKey(hkey);
}
void GetUserVariablePath(){
static const char path[] = "VVS_LOGGING_PATH" ; //Variable Name
static BYTE buffer1[1000000] ;
DWORD buffsz1 = sizeof(buffer1) ;
{
//HKEY_CURRENT_USER\Environment
const char key_name[] = "Environment";
HKEY key ;
if( RegOpenKeyExA( HKEY_CURRENT_USER, key_name, 0, KEY_QUERY_VALUE, std::addressof(key) ) == 0 &&
RegQueryValueExA( key, path, nullptr, nullptr, buffer1, std::addressof(buffsz1) ) == 0 )
{
std::cout << "The updated value of the user variable is : " << reinterpret_cast<const char*>(buffer1) << '\n' ;
}
}
}
int main()
{
SetUserVariablePath();
GetUserVariablePath();
return 0;
}

How to initialize argv[i]?

I am trying to initialize argv[i] to the value of "C:\Games\World_of_Tanks\res\packages\gui.pkg" with a const char* pointer. Can I get some help doing this as I am new to programming.
#include <windows.h>
#include <cstdio>
void pf(const char* name)
{
HANDLE file = CreateFile(name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if(file == INVALID_HANDLE_VALUE) { printf("couldn't open %s\n", name); return; };
unsigned int len = GetFileSize(file, 0);
HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, 0);
if(mapping == 0) { printf("couldn't map %s\n", name); return; }
const char* data = (const char*) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
if(data)
{
printf("prefetching %s... ", name);
// need volatile or need to use result - compiler will otherwise optimize out whole loop
volatile unsigned int touch = 0;
for(unsigned int i = 0; i < len; i += 4096)
touch += data[i];
}
else
printf("couldn't create view of %s\n", name);
UnmapViewOfFile(data);
CloseHandle(mapping);
CloseHandle(file);
}
int main(int argc, const char** argv)
{
if(argc >= 2) for(int i = 1; argv[i]; ++i) pf(argv[i]);
return 0;
}
The value of a const charcan not be changed. What is it you want to do?
If you want a value of the argv array in the main function to be set you need to execute the program with a command line argument like:
program argument argument etc
Edit from comment info:
If you want to run the pffunction on program start you could add
pf("C:\Games\World_of_Tanks\res\packages\gui.pkg"); // this might need to be escaped...
in the main function.
You can just use another array
const char *myargv[] = { "pgmname",
"my_first_filename.dat",
"my_second_filename.dat",
NULL };
argv = myargv;
argc = 3;
If this is just to be able to run the program from an IDE note however that there is for sure a GUI option for setting the command line arguments for the program.

How to CreateFileMapping in C++?

I am coding a game preloader (a simple program that loads certain files [maps] into cache before starting the program. I was told to use CreateFileMapping which I am still unsure whether it loads it into the physical or virtual memory...
Anyway, where would I put what files I need to load?
Here is my code (actually coded by someone else on stack overflow who told me to use it)
#include <windows.h>
#include <cstdio>
void pf(const char* name) {
HANDLE file = CreateFile(name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if(file == INVALID_HANDLE_VALUE) { printf("couldn't open %s\n", name); return; };
unsigned int len = GetFileSize(file, 0);
HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, 0);
if(mapping == 0) { printf("couldn't map %s\n", name); return; }
const char* data = (const char*) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
if(data)
{
printf("prefetching %s... ", name);
// need volatile or need to use result - compiler will otherwise optimize out whole loop
volatile unsigned int touch = 0;
for(unsigned int i = 0; i < len; i += 4096)
touch += data[i];
}
else
printf("couldn't create view of %s\n", name);
UnmapViewOfFile(data);
CloseHandle(mapping);
CloseHandle(file);
}
int main(int argc, const char** argv)
{
if(argc >= 2) for(int i = 1; argv[i]; ++i) pf(argv[i]);
return 0;
}
The pf function accepts a file path as its parameter. The touch loop causes the file (or at least 4 KB portions of it) to be loaded into physical memory.

Memory leak when read from file

I'm trying to read data from XML file and store every element ("< some data/>") in vector container vector<TCHAR*> , why the Task Manager shows the memory usage much greater than vector size(~80mb instead of ~59mb) :
#define _UNICODE
#include<tchar.h>
#include<iostream>
#include<windows.h>
#include<vector>
using namespace std;
HANDLE hFile;
HANDLE hThread;
vector<TCHAR*> tokens;
DWORD tokensSize;
DWORD WINAPI Thread(LPVOID lpVoid);
void main()
{
tokensSize = 0;
hFile = CreateFile("db.xml",GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile == INVALID_HANDLE_VALUE) {
cout<<"CreateFile Error # "<<GetLastError()<<endl;
}
DWORD fileSize = GetFileSize(hFile,NULL);
cout<<"fileSize = "<<fileSize<<" bytes = "<<fileSize/1024/1024<<" mb"<<endl;
TCHAR* buffer = new TCHAR[fileSize / sizeof(TCHAR) + 1];
ZeroMemory(buffer,fileSize);
DWORD bytesRead;
if(!ReadFile(hFile,buffer,fileSize,&bytesRead,NULL)){
cout<<"ReadFile Error # "<<GetLastError()<<endl;
}
CloseHandle(hFile);
hThread = CreateThread(NULL,0,Thread,(LPVOID)buffer,0,NULL);
WaitForSingleObject(hThread,INFINITE);
for(int i=0;i<tokens.size();i++)
tokensSize+=(_tcslen(tokens[i])+1)*sizeof(TCHAR);
cout<<"vector size = "<<tokensSize<<" bytes = "<<tokensSize/1024/1024<<" mb"<<endl;
cin.get();
}
DWORD WINAPI Thread(LPVOID lpVoid)
{
wstring entireDB = (TCHAR*)lpVoid;
delete[]lpVoid;
wstring currentElement;
wstring::size_type lastPos = 0;
wstring::size_type next;
next = entireDB.find(_T(">"),lastPos);
TCHAR* szStr;
do
{
currentElement = entireDB.substr(lastPos,next+1-lastPos);
szStr = new TCHAR[currentElement.length()+1];
_tcscpy(szStr,currentElement.c_str());
tokens.push_back(szStr);
lastPos = next+1;
next = entireDB.find(_T(">"),lastPos);
}
while(next != wstring::npos);
entireDB.clear();
return 0;
}
OUTPUT:~
fileSize = 57mb
vectorSize = 58mb
but the TaskManager shows ~ 81mb.
What am I doing wrong?
THNX!
First, as Aesthete as pointed out, you never clear the token vector once you're finished with it. This should be done, or change the token vector to utilize self-cleaning content like std::string or std::wstring.
Which brings me to the side-by-side below. Please review this against your existing code. There are a number of changes you'll want to compare. The one you will likely not see until you cmopile+run is the memory footprint difference, which may surprise you.
Major Changes
Global tokens is now a vector of std::wstring rather than raw wchar_t pointers
Uses MultiByteToWideChar to translate the input file.
Allocates a std::wstring dynamically as the thread parameter. This removes one full copy of the file image. The thread is responsible for deleteing the wstring once finished parsing the content.
Uses _beginthreadex() for starting the thread. The fundamental reason for this is because of the C/C++ runtime usage. In the past the runtime sets up various thread-local-storage that must be properly cleaned, and are so when using _beginthreadex(). It is almost identical to CreateThread(), but honestly I look forward to the day when MS has their stuff together and gives us std::thread officially like the rest of the civilized world.
Minor/Meaningless Changes
Global variables are brought to local scope where appropriate. this means the only real global now is the tokens vector.
The thread procedure now pushes substrings straight to the tokens vector.
uses argv[1] for the filename (easy to debug that way, no other special reason). can be changed back to your hard-coded filename as needed.
I hope this gives you some ideas on cleaning this up, and more importantly, how yoy can do almost the entire task you're given without having to go new and delete nuts.
Notes: this does NOT check the input file for a byte-order-mark. I'm taking it on faith that your claim it is UTF8 is straight-up and doesn't have a BOM at the file beginning. If your input file does have a BOM, you need to adjust the code that reads the file in to account for this.
#include <windows.h>
#include <tchar.h>
#include <process.h>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// global map of tokens
vector<wstring> tokens;
// format required by _beginthreadex()
unsigned int _stdcall ThreadProc(void *p);
int main(int argc, char *argv[])
{
HANDLE hThread = NULL;
std::string xml;
std::wstring* pwstr = NULL;
// check early exit
if (argc != 2)
{
cout << "Usage: " << argv[0] << " filename" << endl;
return EXIT_FAILURE;
}
// use runtime library for reading the file content. the WIN32 CreateFile
// API is required for some things, but not for general file ops.
HANDLE hFile = CreateFileA(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
DWORD dwFileSize = GetFileSize(hFile, NULL);
if (dwFileSize > 0)
{
// allocate a string large enough for the whole file.
std::string xml(dwFileSize, 0);
DWORD bytesRead = 0;
if (ReadFile(hFile, &xml.at(0), dwFileSize, &bytesRead, NULL) && (bytesRead == dwFileSize))
{
// invoke MB2WC to determine wide-char requirements
int ires = MultiByteToWideChar(CP_UTF8, 0, xml.c_str(), -1, NULL, 0);
if (ires > 0)
{
// allocate a wstring for our thread parameter.
pwstr = new wstring(ires, 0);
MultiByteToWideChar(CP_UTF8, 0, xml.c_str(), -1, &pwstr->at(0), ires);
// launch thread. it own the wstring we're sending, including cleanup.
hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, pwstr, 0, NULL);
}
}
}
// release the file handle
CloseHandle(hFile);
}
// wait for potential thread
if (hThread != NULL)
{
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
// report space taken by tokens
size_t tokensSize = 0;
for (vector<wstring>::const_iterator it = tokens.begin(); it != tokens.end(); ++it)
tokensSize += it->size()+1;
cout << "tokens count = " << tokens.size() << endl
<< "tokens size = "<< tokensSize <<" bytes" << endl;
cin.get();
}
// our thread parameter is a dynamic-allocated wstring.
unsigned int _stdcall ThreadProc(void *p)
{
// early exit on null insertion
if (p == NULL)
return EXIT_FAILURE;
// use string passed to us.
wstring* pEntireDB = static_cast<wstring*>(p);
wstring::size_type last = 0;
wstring::size_type next = pEntireDB->find(L'>',last);
while(next != wstring::npos)
{
tokens.push_back(pEntireDB->substr(last, next-last+1));
last = next+1;
next = pEntireDB->find(L'>', last);
}
// delete the wstring (no longer needed)
delete pEntireDB;
return EXIT_SUCCESS;
}
You allocate memory here, in the do-while loop:
szStr = new TCHAR[currentElement.length()+1];
And you never release it with the delete operator