Everytime I call QDir::removeRecursively() my application crashes AFTER having removed the folder containing the files correctly.
Having done some testing I found out that it depends on how I call the function. This is my code:
Recorder::Recorder(ParentClass *parent): QObject(parent){
connect(this,SIGNAL(finishedRec(QString,QString)),this,SLOT(finishedRecording(QString,QString)));
}
void Recorder::start(){
if (!recording){
recording=true;
recThread.reset(new std::thread(&Recorder::recordThread, this));
}
}
void Recorder::stop(){
recording = false;
recThread->join(); recThread.reset();
}
void Recorder::recordThread(){
QString picDir;
QString filename;
//....
while(recording){
//writing frames to folder
}
emit finishedRec(picDir,filename);
}
void Recorder::finishedRecording(QString picDir, QString filename){
QProcess* proc = new QProcess();
vecProcess.push_back(proc);
vecString.push_back(picDir);
proc->start("C:\\ffmpeg.exe", QStringList() <<"-i"<< picDir << "-r"<< "30" << "-vcodec"<< "ffv1" << filename);
connect(proc,SIGNAL(finished(int)),this,SLOT(finishedProcess()));
}
void Recorder::finishedProcess(){
for (int i=0; i<vecProcess.size();i++){
if(vecProcess.at(i)->state()==QProcess::NotRunning){
delete vecProcess.at(i);
vecProcess.erase(vecProcess.begin() + i);
QString folderToRemove=vecString.at(i);
folderToRemove.chop(12);
qDebug() << folderToRemove;
QDir dir(folderToRemove);
dir.removeRecursively();
vecString.erase(vecString.begin() + i);
}
}
}
Only if I leave dir.removeRecursively() in, my application will always crash. Without it everything works as intended. Even deleting all the files with
QDir dir(path);
dir.setNameFilters(QStringList() << "*.*");
dir.setFilter(QDir::Files);
foreach(QString dirFile, dir.entryList()){
dir.remove(dirFile);
}
will cause a crash AFTRER all the files were deleted.
I'm running my recordThead as a std::unique_ptr<std::thread>. I did try to run the thread as a QThread but that gave me the exact same result. If dir.removeRecursively() was called the program will crash after finishing the event in finishedProcess()
Calling removeRecursively() in a different event loop works. Why doesn't it work when using it in a SLOT like shown in my example?
vector erase effectively reduces the container size by the number of elements removed, which are destroyed.
// one suspect
vecProcess.erase(vecProcess.begin() + i);
// another suspect
vecString.erase(vecString.begin() + i);
And you call that in a loop where 'i' gets incremented? Should eventually attempt to erase something beyond the vector size. I would just release entire container if possible after the loop finished or used list. And maybe you don't need to store pointers in those containers but values (?). Storing pointers to objects allocated by you makes you to release the one by one and sometimes, yes, justified but with C++ 11 and move semantics it is not always the case.
Related
I want to create a list of COM ports in a sub menu that is updated every time the sub menu is viewed.
My plan:
Create a list of objects with data about each detected port, up to 32 object pointers. Example: comDetected *COMsFound[MAX_COM_DETECT]; (working)
Delete() old menu entries (working)
Create a new menu upon EVT_MENU_OPEN() with AppendRadioItem() (working)
Use EVT_MENU() to run the same function for each COM port selection
How do I determine in the event handling function (from wxCommandEvent?) which menu option caused the event? Without this information, I will need 32 separate functions.
Is there a more dynamic way to create the objects and events to avoid the arbitrary limit of 32 I have created?
Edit - This is what I have now for menu re-creation, which seems to be working:
Re-edit - not so good, as explained by bogdan
void FiltgenFrame::OnMenuOpen(wxMenuEvent& event)
{
//fill in COM port menu when opened
if(event.GetMenu() == COMSubMenu)
{
int i;
wxString comhelp;
//re-scan ports
comport->getPorts();
if(comport->COMdetectChanged == 1)
{
comport->currentCOMselection = 0; //when menu is regenerated, selection returns to 0
//get rid of old menu entries
for(i = 0; i < comport->oldnumCOMsFound; i++)
{
COMSubMenu->Delete(FILTGEN_COM1 + i);
COMSubMenu->Unbind(wxEVT_MENU, [i](wxCommandEvent&)
{
logMsg(DBG_MENUS, ACT_NORMAL, "menu COM select index: %d\n", i);
}, FILTGEN_COM1 + i);
}
//add new menu entries
for(i = 0; i < comport->numCOMsFound; i++)
{
comhelp.Printf("Use %s", comport->COMsFound[i]->name);
COMSubMenu->AppendRadioItem(FILTGEN_COM1 + i, comport->COMsFound[i]->name, comhelp);
COMSubMenu->Bind(wxEVT_MENU, [i](wxCommandEvent&)
{
comport->currentCOMselection = i;
logMsg(DBG_MENUS, ACT_NORMAL, "menu COM select index: %d\n", i);
}, FILTGEN_COM1 + i);
}
}
}
}
Edit - re-worked code 1-29-15. Broke apart OnMenuOpen and recreateCOMmenu due to factors unrelated to this question. Added COMselectionHandler because of advice.
void FiltgenFrame::COMselectionHandler(wxCommandEvent& event)
{
comport->currentCOMselection = event.GetId() - FILTGEN_COM1;
logMsg(DBG_MENUS, ACT_NORMAL, "COM menu select index: %d\n", comport->currentCOMselection);
}
void FiltgenFrame::recreateCOMmenu()
{
logMsg(DBG_MENUS, ACT_NORMAL, "FiltgenFrame::recreateCOMmenu():\n");
int i;
wxString comhelp;
//re-scan ports
comport->getPorts();
if(comport->COMdetectChanged == 1)
{
comport->currentCOMselection = 0; //when menu is regenerated, selection returns to 0
//get rid of old menu entries
for(i = 0; i < comport->oldnumCOMsFound; i++)
{
COMSubMenu->Delete(FILTGEN_COM1 + i);
COMSubMenu->Unbind(wxEVT_MENU, &FiltgenFrame::COMselectionHandler, this, FILTGEN_COM1 + i);
}
//add new menu entries
for(i = 0; i < comport->numCOMsFound; i++)
{
comhelp.Printf("Use %s", comport->COMsFound[i]->name);
COMSubMenu->AppendRadioItem(FILTGEN_COM1 + i, comport->COMsFound[i]->name, comhelp);
COMSubMenu->Bind(wxEVT_MENU, &FiltgenFrame::COMselectionHandler, this, FILTGEN_COM1 + i);
}
}
}
void FiltgenFrame::OnMenuOpen(wxMenuEvent& event)
{
//fill in COM port menu when opened
if(event.GetMenu() == COMSubMenu)
{
recreateCOMmenu();
}
}
Since dynamic seems to be the key word here, I would go for dynamic event handling (actually, I always go for dynamic event handling using Bind, it's so much nicer than the alternatives):
auto pm = new wxMenu(); //I suppose you're adding this to an existing menu.
std::wstring port_str = L"COM";
int id_base = 77; //However you want to set up the IDs of the menu entries.
for(int port_num = 1; port_num <= 32; ++port_num)
{
int id = id_base + port_num;
pm->AppendRadioItem(id, port_str + std::to_wstring(port_num));
pm->Bind(wxEVT_MENU, [port_num](wxCommandEvent&)
{
//Do something with the current port_num; for example:
wxMessageBox(std::to_wstring(port_num));
//You can also capture id if you prefer, of course.
}, id);
}
In the lambda expression, we capture the port number by value, so, for each iteration, the current port_num will be captured. This achieves exactly what you asked for: the same function (the operator() of the lambda's closure type) associated with each menu entry. The function knows the entry for which it was called because it has access to the captured port_num value, stored in the lambda's closure object - a small object, most likely the size of one int in this case.
To avoid a fixed limit on the number of objects, you can simply store them in a std::vector. If you want the vector to own the objects (have them destroyed automatically when the vector is destroyed), then you can store them directly in a std::vector<comDetected>. If something else owns the objects and takes care of destroying them separately, you could use std::vector<comDetected*>.
UPDATE: When writing my first solution, I didn't realize you'll want to Unbind and re-bind those event handlers; pretty obvious in hindsight, really, but... anyway, my mistake, sorry.
Here's the problem: as far as I can tell, there's no straightforward way to Unbind a lambda function object that was passed directly to Bind as I did in my example. Simply calling Unbind as you're doing in your updated code isn't going to work, because that Unbind will try to find an event handler that was installed by a corresponding call to Bind with the exact same arguments. That won't happen for the reasons explained in the next section (there's also an explanation for why it seems to work), but you might be more interested in solutions, so I'll start with those.
Solution 1 (the best one in your case): Forgo using lambdas; just use either a free function or a member function pointer. In this case, you'll need to get the menu entry ID from evt.GetId() and get the port index from it; something like this:
void handler_func(wxCommandEvent& evt)
{
int i = evt.GetId() - FILTGEN_COM1;
comport->currentCOMselection = i;
logMsg(DBG_MENUS, ACT_NORMAL, "menu COM select index: %d\n", i);
}
Then, your code would look like this:
void FiltgenFrame::OnMenuOpen(wxMenuEvent& event)
{
/* ... */
COMSubMenu->Unbind(wxEVT_MENU, handler_func, FILTGEN_COM1 + i);
/* ... */
COMSubMenu->Bind(wxEVT_MENU, handler_func, FILTGEN_COM1 + i);
/* ... */
}
The example above is using a free function. You can also use a member function - more info here.
Solution 2: In case you can rebuild that menu at some other time than EVT_MENU_OPEN(), you could go for destroying the whole wxMenu and rebuilding and inserting it into its parent menu in the right place. Destroying the old menu object will take care of all the dynamic event handlers bound to it, so you don't need to Unbind them. However, destroying the menu just before it's displayed doesn't sound like a good idea - I haven't tried it, but as far as I can tell it won't work, or behave in highly platform-dependent ways.
Here are the reasons for which Unbind won't work directly with lambdas:
The object generated by a lambda expression has a unique type. Even if you copy-paste the exact same lambda expression to another place in your code, that second lambda will generate a closure object of a type different from the one generated by the original lambda. Since Unbind checks the type of the functor argument against the types of the installed handlers, it will never find a match.
Even if we got around the problem above, there's another one: the function object passed to Unbind also needs to have the same address as the one passed to the corresponding Bind. The object generated when the lambda expression is passed directly to Bind is a temporary (it will typically be allocated on the stack), so making any assumptions about its address across function calls is just incorrect.
We can get around the two problems above (store the closure objects separately somewhere and so on), but I think any such solution is far too cumbersome to be worth considering - it will negate all the advantages of the lambda-based solution.
Here's why it seems to work in your code:
If Unbind doesn't find an event handler to remove, it just returns false; all existing handlers remain in there. Later on, Bind adds a new handler for the same event type and same entry ID at the front of the event handler list, so newer handlers are called first. Unless a handler calls evt.Skip() before returning, the event is considered handled after the handler returns and no other handlers are called.
Even though it sort of works as you expect, letting all those old unused handlers accumulate in the list every time the menu is rebuilt isn't a good idea, obviously.
I am developing a multithreaded C++ application, and developed a module for logging. The logging module is a static class, which I call using Logger::Log(string file, string message), that fills a static queue with a pair<string*,string*> The queue itself is a queue<<pair<string*,string*>*>. Everything is saved as a pointer, as I was trying to avoid garbage collection, and believe pointer variables need specific delete to free the memory.
Now, when one of the threads wants to log something, it calls the Log method, which in turn appends to the end of the queue.
Another thread runs through the queue, pops items and writes them to the designated file.
For some reason, some of the text being written to the file is corrupted, as I am losing part of the begginning or the end of the message.
For example, if I call Log("file", "this is my message"), inside the Log method I am prepending a timestamp, and creating a new string, because I thought the original string might be overwritten, but it still happens.
The problem is that in some situations, what is being written to the file is the timestamp, plus only the end of the message.
This is the full code of the Logger class:
#include "Logger.h"
queue<pair<string*, string*>*> Logger::messages;
boost::mutex Logger::loggerLock;
void Logger::CleanOldFiles(vector<string> files){
for (vector<string>::iterator it = files.begin(); it != files.end(); ++it) {
string filePath = boost::filesystem::current_path().string() + "\\" + *it;
int result = remove(filePath.c_str());
}
}
void Logger::Init() {
Logger::messages = queue<pair<string*, string*>*>();
boost::thread workerThread(Logger::Process);
//workerThread.start_thread();
}
void Logger::RawLog(string file, string message) {
loggerLock.lock();
string *f = new string(file);
string *m = new string(message + "\n");
messages.push(new pair<string*, string*>(f, m));
loggerLock.unlock();
}
void Logger::Log(string file, string message) {
loggerLock.lock();
string *f = new string(file);
string *m = new string(Functions::CurrentTime() + " (" + boost::lexical_cast<string>(boost::this_thread::get_id()) + "): " + message.c_str() + "\n");
messages.push(new pair<string*, string*>(f, m));
loggerLock.unlock();
}
void Logger::Process() {
while (true) {
if (Logger::messages.size() == 0) {
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
continue;
}
loggerLock.lock();
pair<string*, string*> *entry = messages.front();
messages.pop();
loggerLock.unlock();
ofstream file(boost::filesystem::current_path().string() + "\\" + *(entry->first), ofstream::binary | ofstream::app);
file.write(entry->second->c_str(), entry->second->length());
file.close();
delete entry->first;
delete entry->second;
delete entry;
//cout << entry->second;
}
}
I hope I made myself clear enough...
I do not understand why this is happening, can anyone give me some hints on how to avoid this?
Thanks in advance.
The Logger::Log must be made MT-safe, otherwise you can get two or more threads trying to log something simultaneously. A simplest way to make it MT-safe is a mutex.
std::queue is not thread-safe. You need to lock access to all the shared objects or to use thread-safe queue implementation like TBB provides.
if (Logger::messages.size() == 0) {
Because messages isn't thread safe, you can't call any functions on it when you don't hold the lock. Also, you are still missing delete calls for the string*s.
You can always just do this:
void Logger::Process()
{
while (true)
{
loggerLock.lock();
if (Logger::messages.size() == 0)
break;
loggerLock.unlock();
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
}
pair<string*, string*> *entry = messages.front();
messages.pop();
loggerLock.unlock();
ofstream file(boost::filesystem::current_path().string() + "\\" +
*(entry->first), ofstream::binary | ofstream::app);
file.write(entry->second->c_str(), entry->second->length());
delete entry->first;
delete entry->second;
file.close();
}
However, for future reference:
1) Don't use pointers this way. Just use a queue of pairs of strings. The pointers don't buy you anything.
2) Use some sane synchronization mechanism like a condition variable. Don't use sleep for synchronization.
3) Use scoped locks and RAII so you don't forget an unlock.
I apologize for the work I might have caused for all trying to help me, but I corrected the issue. This was actually no memory corruption issue, and my assumption made me search for something where there was no problem.
The issue was on the calling threads, and on the form I was creating the log strings. I was concatenating strings in the wrong way...damn those other programming languages ;)
I was doing something such as Logger::Log("Message: " + integerVariable), which is fact was shifting the string to the right (at least I believe that was what it was doing). When I casted all those variables to strings, everything started working. Thank you for all your help anyway.
I am writing a Qt application that deals with scheduling employees. The header data for the main QTableView is a pointer to a QStringList. The headerData() function works correctly, but when i add a string to the list elsewhere, it appends the entire list including the new string to the end of the list.
For example, if i have the list 1,2,3 and i append 4 to it, then iterating through the list based on the pointer gives the result 1,2,3,1,2,3,4. I don't know a better way than using pointers to have multiple classes access the same data. Does anyone know how to fix the repeating list?
Example Code
//function to save a new employee in memory
bool EmployeeViewDialog::saveEmployee(Employee *e)
{
employees->insert(e->name,e);
*employeeNames << e->name;
for (int i = 0; i < employeeNames->length(); i++) {
qDebug() << employeeNames->at(i);
}
QList<QStandardItem*> items;
items << new QStandardItem(e->name);
items << new QStandardItem(e->id);
items << new QStandardItem(e->phone);
items << new QStandardItem(e->email);
model->appendRow(items);
return true;
}
The append was just changed to the << method. It is the employeeNames << e->name; line.
The for loop iterates through the list and does the same thing as what happens in the external class.
So this is a reduced version of my main / Initializer function. When I call it and it has to add any items to the players inventor, I get a Debug Assertation Failed error.
It seems to me like I am mixing up the scope somewhat?
Am I declaring something new inside the scope of the function, and then not being able to access it again out in main?
I tried a few things inside the function, like using Getters/Setters instead of assigning is completely, like p_player = p but I don't think that actually deals with the problem at all, and I'm kind of confused.
int main()
{
Array<Item> items(3);
string itemsfilename = "itemsfile.txt";
Initializer::InitializeItems(items, itemsfilename);
Login login;
Player p1;
string filename = login.LoginToGame();
Initializer::InitializePlayer(p1, rooms, items, 3, filename);
}
void Initializer::InitializePlayer(Player& p_player, HashTable<string, Room>& p_rooms, Array<Item>& p_items, int p_numItems, std::string& p_filename)
{
ifstream playerfile(p_filename);
int inventorycount = 0;
//all the stuff needed to make a player
std::string name;
int health;
int confidence;
int humor;
int speed;
std::string room;
Room* currentRoom;
Inventory inventory(100);
//reading in values from file
for(int i = 0; i < inventorycount; i++)
{
playerfile.getline(value, 256);
std::string item(value);
for(int j = 0; j < p_numItems; j++)
{
if(p_items[j].GetName() == item)
{
inventory.AddItem(&(p_items[j])); //This line taken out, removes the error.
}
}
}
Player p(name, health, confidence, humor, speed, currentRoom, inventory);
p_player = p;
}
AddItem() takes a pointer to an item, and then appends it to it's DLinkedList.
Edit:
The error I get is
Debug Assertation Failed!
Program: zzz
File f:\dd/vctools/crt_bld/self_x86/crt/src/dbgdel.cpp
Line: 52
Expression: _Block_TYPE_IS_VALID(pHead->nBlockUse)
AddItem() Code:
bool AddItem(Item* p_item)
{
if(p_item->GetWeight() + m_weight <= m_maxWeight)
{
m_inventory.Append(p_item);
m_weight += p_item->GetWeight();
}
else
{
return false;
}
return true;
}
Ok, so we still don't have the code that actually causes the problem, but I'm pretty certain I know what's going on, and to avoid getting into a "20 questions of add more code" - there's two possible scenarios:
Items is an array of objects, and you store pointers to them in your m_inventory container. When destroying this container, the objects are destroyed by calling delete on the items - which doesn't work since the content is not allocated from the heap.
When you copy the inventory the m_inventory container is not appropriately copied, and the contents fall apart because the pointers to the storage is failing.
If this doesn't help, then please try to reduce your code to something that only shows this problem, without using files that we don't know the content of and can be posted as a complete program in the question with all the code necessary [remove any other code that isn't needed], so we can see EVERYTHING. Currently, we're only seeing a few bits of the code, and the problem is almost certainly DIRECTLY in the code you've shown us.
I'm trying to fix this problem which seems like I am accessing at an out of range index, but VS fails to stop where the error occurred leaving me confused about what's causing this.
The Error:
Debug Assertion Failed! Program: .... File: c:\program files\microsoft visual studio 10.0\vc\include\vector Line: 1440 Expression: String subscript out of range
What the program does:
There are two threads:
Thread 1:
The first thread looks (amongst other things) for changes in the current window using GetForegroundWindow(), the check happens not on a loop but when a WH_MOUSE_LL event is triggered. The data is split into structs of fixed size so that it can be sent to a server over tcp. The first thread and records the data (Window Title) into an std::list in the current struct.
if(change_in_window)
{
GetWindowTextW(hActWin,wTitle,256);
std::wstring title(wTitle);
current_struct->titles.push_back(title);
}
Thread 2:
The second thread is called looks for structs not send yet, and it puts their content into char buffers so that they can be sent over tcp. While I do not know exactly where the error is, looking from the type of error it was to do either with a string or a list, and this is the only code from my whole application using lists/strings (rest are conventional arrays). Also commenting the if block as mentioned in the code comments stops the error from happening.
BOOL SendStruct(DATABLOCK data_block,bool sycn)
{
[..]
int _size = 0;
// Important note, when this if block is commented the error ceases to exist, so it has something to do with the following block
if(!data_block.titles.empty()) //check if std::list is empty
{
for (std::list<std::wstring>::iterator itr = data_block.titles.begin(); itr != data_block.titles.end() ; itr++) {
_size += (((*itr).size()+1) * 2);
} //calculate size required. Note the +1 is for an extra character between every title
wchar_t* wnd_wbuffer = new wchar_t[_size/2](); //allocate space
int _last = 0;
//loop through every string and every char of a string and write them down
for (std::list<std::wstring>::iterator itr = data_block.titles.begin(); itr != data_block.titles.end(); itr++)
{
for(unsigned int i = 0; i <= (itr->size()-1); i++)
{
wnd_wbuffer[i+_last] = (*itr)[i] ;
}
wnd_wbuffer[_last+itr->size()] = 0x00A6; // separator
_last += itr->size()+1;
}
unsigned char* wnd_buffer = new unsigned char[_size];
wnd_buffer = (unsigned char*)wnd_wbuffer;
h_io->header_w_size = _size;
h_io->header_io_wnd = 1;
Connect(mode,*header,conn,buffer_in_bytes,wnd_buffer,_size);
delete wnd_wbuffer;
}
else
[..]
return true;
}
My attempt at thread synchronization:
There is a pointer to the first data_block created (db_main)
pointer to the current data_block (db_cur)
//datablock format
typedef struct _DATABLOCK
{
[..]
int logs[512];
std::list<std::wstring> titles;
bool bPrsd; // has this datablock been sent true/false
bool bFull; // is logs[512] full true/false
[..]
struct _DATABLOCK *next;
} DATABLOCK;
//This is what thread 1 does when it needs to register a mouse press and it is called like this:
if(change_in_window)
{
GetWindowTextW(hActWin,wTitle,256);
std::wstring title(wTitle);
current_struct->titles.push_back(title);
}
RegisterMousePress(args);
[..]
//pseudo-code to simplify things , although original function does the exact same thing.
RegisterMousePress()
{
if(it_is_full)
{
db_cur->bFull= true;
if(does db_main exist)
{
db_main = new DATABLOCK;
db_main = db_cur;
db_main->next = NULL;
}
else
{
db_cur->next = new DATABLOCK;
db_cur = db_cur->next;
db_cur->next = NULL;
}
SetEvent(eProcessed); //tell thread 2 there is at least one datablock ready
}
else
{
write_to_it();
}
}
//this is actual code and entry point of thread 2 and my attempy at synchronization
DWORD WINAPI InitQueueThread(void* Param)
{
DWORD rc;
DATABLOCK* k;
SockWClient writer;
k = db_main;
while(true)
{
rc=WaitForSingleObject(eProcessed,INFINITE);
if (rc== WAIT_OBJECT_0)
{
do
{
if(k->bPrsd)
{
continue;
}
else
{
if(!k)
{break;}
k->bPrsd = TRUE;
#ifdef DEBUG_NET
SendStruct(...);
#endif
}
if(k->next == NULL || k->next->bPrsd ==TRUE || !(k->next->bFull))
{
ResetEvent(eProcessed);
break;
}
} while (k = k->next); // next element after each loop
}
}
return 1;
}
Details:
Now something makes me believe that the error is not in there, because the substring error is very rare. I have been only able to reproduce it with 100% chance when pressing Mouse_Down+Wnd+Tab to scroll through windows and keeping it pressed for some time (while it certainly happened on other cases as well). I avoid posting the whole code because it's a bit large and confusion is unavoidable. If the error is not here I will edit the post and add more code.
Thanks in advance
There does not appear to be any thread synchronization here. If one thread reads from the structure while the other writes, it might be read during initialization, with a non-empty list containing an empty string (or something invalid, in between).
If there isn't a mutex or semaphore outside the posted function, that is likely the problem.
All the size calculations appear to be valid for Windows, although I didn't attempt to run it… and <= … -1 instead of < in i <= (itr->size()-1) and 2 instead of sizeof (wchar_t) in new wchar_t[_size/2](); are a bit odd.
The problem with your code is that while thread 2 correctly waits for the data and thread 1 correctly notifies about them, thread 2 doesn't prevent thread 1 from doing anything with them under its hands while it still process the data. The typical device used to solve such problem is the monitor pattern.
It consist of one mutex (used to protect the data, held anytime you access them) and a condition variable (=Event in Windows terms), which will convey the information about new data to the consumer.
The producer would normally obtain the mutex, produce the data, release the mutex, then fire the event.
The consumer is more tricky - it has to obtain the mutex, check if new data hasn't become available, then wait for the Event using the SignalObjectAndWait function that temporarily releases the mutex, then process newly acquired data, then release the mutex.