In my application i'm getting series of Windows events and i want to compress them and process unique events in c++.
For example: Event W1, W2, W3, W4 ...., Event E1, E2... etc.,
If I'm getting only W1 series in timeframe I want to process only one event by compressing remaining events of same series.
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <process.h>
#include <list>
#include <vector>
#include<Windows.h>
#include <future>
#include <fstream>
static const char* WFEVENTNAME_EVENT1 = "Global\\WFEVENTNAME_EVENT1";
static const char* WFEVENTNAME_EVENT2 = "Global\\WFEVENTNAME_EVENT2";
static const char* WFEVENTNAME_EVENT3 = "Global\\WFEVENTNAME_EVENT3";
static const char* WFEVENTNAME_EVENT4 = "Global\\WFEVENTNAME_EVENT4";
static const char* WFEVENTNAME_EVENT5 = "Global\\WFEVENTNAME_EVENT5";
static const char* WFEVENTNAME_EVENT6 = "Global\\WFEVENTNAME_EVENT6";
static const char* WFEVENTNAME_EVENT7 = "Global\\WFEVENTNAME_EVENT7";
static const char* WFEVENTNAME_EVENT8 = "Global\\WFEVENTNAME_EVENT8";
static const char* WFEVENTNAME_EVENT9 = "Global\\WFEVENTNAME_EVENT9";
static const char* WFEVENTNAME_EVENT10 = "Global\\WFEVENTNAME_EVENT10";
static const char* WFEVENTNAME_EVENT11 = "Global\\WFEVENTNAME_EVENT11";
std::ofstream outfile;
typedef std::lock_guard<std::mutex> lockMutex;
typedef std::unique_lock<std::mutex> ulock;
class Handler1
{
public:
bool ProcessMessage(std::string messageName)
{
printf("Processed Handler1\n");
return true;
}
};
class Handler2
{
public:
bool ProcessMessage(std::string messageName)
{
printf("Processed Handler2\n");
return true;
}
};
class Handler3
{
public:
bool ProcessMessage(std::string messageName)
{
printf("Processed Handler3\n");
return true;
}
};
class Handler4
{
public:
bool ProcessMessage(std::string messageName)
{
printf("Processed Handler4\n");
return true;
}
};
class Handler5
{
public:
bool ProcessMessage(std::string messageName)
{
printf("Processed Handler5\n");
return true;
}
};
class Handler6
{
public:
bool ProcessMessage(std::string messageName)
{
printf("Processed Handler6\n");
return true;
}
};
unsigned _stdcall threadFuncToCollectSenderEvents(void* senderObject);
unsigned _stdcall threadFuncToProcessSenderEvents(void* senderObject);
class MessagingEventsNotifier
{
public:
MessagingEventsNotifier()
{
_beginthreadex(0, 0, threadFuncToCollectSenderEvents, this, 0, 0);
_beginthreadex(0, 0, threadFuncToProcessSenderEvents, this, 0, 0);
}
std::list<std::string> mySenderEvents;
std::mutex myMutex;
/// To notify to process the collected event
std::condition_variable myConsumer;
Handler1* myConnectionHandler;
Handler2* myHandler2;
Handler3* myLandmarkWorkflowHandler;
Handler4* myHandler4;
Handler5* myHandler5;
Handler6* myHandler6;
std::vector<HANDLE> myThreadHandles;
};
unsigned _stdcall threadFuncToCollectSenderEvents(void* senderObject)
{
MessagingEventsNotifier *senderEventObject = static_cast<MessagingEventsNotifier*>(senderObject);
while (true)
{
HANDLE hEvents[8];
hEvents[0] = CreateEventA(NULL, false, false, WFEVENTNAME_EVENT3);
hEvents[1] = CreateEventA(NULL, false, false, WFEVENTNAME_EVENT9);
hEvents[2] = CreateEventA(NULL, false, false, WFEVENTNAME_EVENT5);
hEvents[3] = CreateEventA(NULL, false, false, WFEVENTNAME_EVENT6);
hEvents[4] = CreateEventA(NULL, false, false, WFEVENTNAME_EVENT1);
hEvents[5] = CreateEventA(NULL, false, false, WFEVENTNAME_EVENT7);
hEvents[6] = CreateEventA(NULL, false, false, WFEVENTNAME_EVENT2);
hEvents[7] = CreateEventA(NULL, false, false, WFEVENTNAME_EVENT10);
DWORD result = WaitForMultipleObjects(8, hEvents, false, INFINITE);
lockMutex l(senderEventObject->myMutex);
if ((result - WAIT_OBJECT_0) == 0)
{
senderEventObject->mySenderEvents.push_back(WFEVENTNAME_EVENT3);
}
else if ((result - WAIT_OBJECT_0) == 1)
{
senderEventObject->mySenderEvents.push_back(WFEVENTNAME_EVENT9);
}
else if ((result - WAIT_OBJECT_0) == 2)
{
senderEventObject->mySenderEvents.push_back(WFEVENTNAME_EVENT5);
}
else if ((result - WAIT_OBJECT_0) == 3)
{
senderEventObject->mySenderEvents.push_back(WFEVENTNAME_EVENT6);
}
else if ((result - WAIT_OBJECT_0) == 4)
{
senderEventObject->mySenderEvents.push_back(WFEVENTNAME_EVENT1);
}
else if ((result - WAIT_OBJECT_0) == 5)
{
senderEventObject->mySenderEvents.push_back(WFEVENTNAME_EVENT7);
}
else if ((result - WAIT_OBJECT_0) == 6)
{
senderEventObject->mySenderEvents.push_back(WFEVENTNAME_EVENT2);
}
else if ((result - WAIT_OBJECT_0) == 7)
{
senderEventObject->mySenderEvents.push_back(WFEVENTNAME_EVENT10);
}
senderEventObject->myConsumer.notify_one();
}
return true;
}
unsigned _stdcall threadFuncToProcessSenderEvents(void* senderObject)
{
MessagingEventsNotifier *senderEventObject = static_cast<MessagingEventsNotifier*>(senderObject);
ulock unlockMutex(senderEventObject->myMutex);
while (true)
{
senderEventObject->myConsumer.wait(unlockMutex);
if (senderEventObject->mySenderEvents.size() <= 0)
{
continue;
}
senderEventObject->mySenderEvents.unique();
for (std::list<std::string>::iterator it = senderEventObject->mySenderEvents.begin();
it != senderEventObject->mySenderEvents.end(); ++it)
{
i++;
std::string str = "Count = " + std::to_string(i) + "\n";
outfile.write(str.c_str(), str.size());
outfile.flush();
printf("Processed Events Count: %d\n", i);
std::string eventName = *it;
if (eventName == WFEVENTNAME_EVENT3)
{
senderEventObject->myLandmarkWorkflowHandler->ProcessMessage(WFEVENTNAME_EVENT3);
Sleep(10);
}
else if (eventName == WFEVENTNAME_EVENT9)
{
senderEventObject->myHandler2->ProcessMessage(WFEVENTNAME_EVENT9);
Sleep(10);
}
else if (eventName == WFEVENTNAME_EVENT5)
{
senderEventObject->myHandler5->ProcessMessage(WFEVENTNAME_EVENT5);
Sleep(10);
}
else if (eventName == WFEVENTNAME_EVENT6)
{
senderEventObject->myHandler5->ProcessMessage(WFEVENTNAME_EVENT6);
Sleep(10);
}
else if (eventName == WFEVENTNAME_EVENT1)
{
senderEventObject->myConnectionHandler->ProcessMessage(WFEVENTNAME_EVENT1);
Sleep(10);
}
else if (eventName == WFEVENTNAME_EVENT7)
{
senderEventObject->myConnectionHandler->ProcessMessage(WFEVENTNAME_EVENT7);
Sleep(10);
}
else if (eventName == WFEVENTNAME_EVENT2)
{
senderEventObject->myHandler4->ProcessMessage(WFEVENTNAME_EVENT2);
Sleep(10);
}
else if (eventName == WFEVENTNAME_EVENT10)
{
senderEventObject->myHandler6->ProcessMessage(WFEVENTNAME_EVENT10);
Sleep(10);
}
}
senderEventObject->mySenderEvents.clear();
}
}
int main()
{
MessagingEventsNotifier obj;
for (int i = 1; i < 50; i++)
{
HANDLE handle1 = CreateEvent(NULL, 0, 0, WFEVENTNAME_EVENT10);
SetEvent(handle1);
Sleep(5);
if (i % 2 == 0)
{
HANDLE handle2 = CreateEvent(NULL, 0, 0, WFEVENTNAME_EVENT3);
SetEvent(handle2);
Sleep(5);
}
if (i % 3 == 0)
{
HANDLE handle3 = CreateEvent(NULL, 0, 0, WFEVENTNAME_EVENT2);
SetEvent(handle3);
Sleep(5);
}
if (i % 5 == 0)
{
HANDLE handle3 = CreateEvent(NULL, 0, 0, WFEVENTNAME_EVENT6);
SetEvent(handle3);
Sleep(5);
}
if (i % 10 == 0)
{
HANDLE handle4 = CreateEvent(NULL, 0, 0, WFEVENTNAME_EVENT9);
SetEvent(handle4);
Sleep(5);
}
}
HANDLE hEvent = CreateEventA(NULL, false, false, "SSSS");
DWORD result = WaitForSingleObject(hEvent, INFINITE);
}
There are two threads:
one will collect events
another will process them sequentially.
My question is: whilst processing we might miss few events to collect; how to handle this scenario ?
I wanted to design the windows events mechanism and compression too.
Please help me in achieving this kind of mechanism.
Maintain a list of events and the timestamps of when they were last processed.
When an you encounter an event, search for it in the list:
if found, check if required time has passed,
if passed, process it and update its timestamp
else ignore
if not found, add it to list with the timestamp and process it.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
i have some c++ project after a release of support c++20, i want to upgrade my makefile std support 17 to 20 after that point my compiler (gcc10.2) give me a error like this ;
Error
In file included from /usr/local/lib/gcc10/include/c++/bits/node_handle.h:39,
from /usr/local/lib/gcc10/include/c++/bits/stl_tree.h:72,
from /usr/local/lib/gcc10/include/c++/map:60,
from AsyncSQL.h:10,
from AsyncSQL.cpp:4:
/usr/local/lib/gcc10/include/c++/optional: In function 'constexpr std::strong_ordering std::operator<=>(const std::optional<_Tp>&, std::nullopt_t)':
/usr/local/lib/gcc10/include/c++/optional:1052:24: error: invalid operands of types 'bool' and 'int' to binary 'operator<=>'
1052 | { return bool(__x) <=> false; }
| ~~~~~~~~~ ^~~
| |
| bool
gmake[2]: *** [Makefile:23: AsyncSQL.o] Error 1
This is my AsyncSQL.cpp ;
#include <sys/time.h>
#include <cstdlib>
#include <cstring>
#include "AsyncSQL.h"
#define MUTEX_LOCK(mtx) pthread_mutex_lock(mtx)
#define MUTEX_UNLOCK(mtx) pthread_mutex_unlock(mtx)
CAsyncSQL::CAsyncSQL(): m_stHost (""), m_stUser (""), m_stPassword (""), m_stDB (""), m_stLocale (""), m_iMsgCount (0), m_iPort (0), m_bEnd (false), m_hThread (0), m_mtxQuery (NULL), m_mtxResult (NULL), m_iQueryFinished (0), m_ulThreadID (0), m_bConnected (false), m_iCopiedQuery (0)
{
memset (&m_hDB, 0, sizeof (m_hDB));
m_aiPipe[0] = 0;
m_aiPipe[1] = 0;
}
CAsyncSQL::~CAsyncSQL()
{
Quit();
Destroy();
}
void CAsyncSQL::Destroy()
{
if (m_hDB.host)
{
sys_log (0, "AsyncSQL: closing mysql connection.");
mysql_close (&m_hDB);
m_hDB.host = NULL;
}
if (m_mtxQuery)
{
pthread_mutex_destroy (m_mtxQuery);
delete m_mtxQuery;
m_mtxQuery = NULL;
}
if (m_mtxResult)
{
pthread_mutex_destroy (m_mtxResult);
delete m_mtxResult;
m_mtxQuery = NULL;
}
}
void* AsyncSQLThread (void* arg)
{
CAsyncSQL* pSQL = ((CAsyncSQL*) arg);
if (!pSQL->Connect())
{
return NULL;
}
pSQL->ChildLoop();
return NULL;
}
bool CAsyncSQL::QueryLocaleSet()
{
if (0 == m_stLocale.length())
{
sys_err ("m_stLocale == 0");
return true;
}
if (mysql_set_character_set (&m_hDB, m_stLocale.c_str()))
{
sys_err ("cannot set locale %s by 'mysql_set_character_set', errno %u %s", m_stLocale.c_str(), mysql_errno (&m_hDB) , mysql_error (&m_hDB));
return false;
}
sys_log (0, "\t--mysql_set_character_set(%s)", m_stLocale.c_str());
return true;
}
bool CAsyncSQL::Connect()
{
if (0 == mysql_init (&m_hDB))
{
fprintf (stderr, "mysql_init failed\n");
return false;
}
if (!m_stLocale.empty())
{
if (mysql_options (&m_hDB, MYSQL_SET_CHARSET_NAME, m_stLocale.c_str()) != 0)
{
fprintf (stderr, "mysql_option failed : MYSQL_SET_CHARSET_NAME %s ", mysql_error(&m_hDB));
}
}
if (!mysql_real_connect (&m_hDB, m_stHost.c_str(), m_stUser.c_str(), m_stPassword.c_str(), m_stDB.c_str(), m_iPort, NULL, CLIENT_MULTI_STATEMENTS))
{
fprintf (stderr, "mysql_real_connect: %s\n", mysql_error(&m_hDB));
return false;
}
my_bool reconnect = true;
if (0 != mysql_options (&m_hDB, MYSQL_OPT_RECONNECT, &reconnect))
{
fprintf (stderr, "mysql_option: %s\n", mysql_error(&m_hDB));
}
m_ulThreadID = mysql_thread_id (&m_hDB);
m_bConnected = true;
return true;
}
bool CAsyncSQL::Setup (CAsyncSQL* sql, bool bNoThread)
{
return Setup (sql->m_stHost.c_str(), sql->m_stUser.c_str(), sql->m_stPassword.c_str(), sql->m_stDB.c_str(), sql->m_stLocale.c_str(), bNoThread, sql->m_iPort);
}
bool CAsyncSQL::Setup (const char* c_pszHost, const char* c_pszUser, const char* c_pszPassword, const char* c_pszDB, const char* c_pszLocale, bool bNoThread, int iPort)
{
m_stHost = c_pszHost;
m_stUser = c_pszUser;
m_stPassword = c_pszPassword;
m_stDB = c_pszDB;
m_iPort = iPort;
if (c_pszLocale)
{
m_stLocale = c_pszLocale;
sys_log (0, "AsyncSQL: locale %s", m_stLocale.c_str());
}
if (!bNoThread)
{
m_mtxQuery = new pthread_mutex_t;
m_mtxResult = new pthread_mutex_t;
if (0 != pthread_mutex_init (m_mtxQuery, NULL))
{
perror ("pthread_mutex_init");
exit (0);
}
if (0 != pthread_mutex_init (m_mtxResult, NULL))
{
perror ("pthread_mutex_init");
exit (0);
}
pthread_create (&m_hThread, NULL, AsyncSQLThread, this);
return true;
}
else
{
return Connect();
}
}
void CAsyncSQL::Quit()
{
m_bEnd = true;
m_sem.Release();
if (m_hThread)
{
pthread_join (m_hThread, NULL);
m_hThread = NULL;
}
}
SQLMsg* CAsyncSQL::DirectQuery (const char* c_pszQuery)
{
if (m_ulThreadID != mysql_thread_id (&m_hDB))
{
sys_log (0, "MySQL connection was reconnected. querying locale set");
while (!QueryLocaleSet());
m_ulThreadID = mysql_thread_id (&m_hDB);
}
SQLMsg* p = new SQLMsg;
p->m_pkSQL = &m_hDB;
p->iID = ++m_iMsgCount;
p->stQuery = c_pszQuery;
if (mysql_real_query (&m_hDB, p->stQuery.c_str(), p->stQuery.length()))
{
char buf[1024];
snprintf (buf, sizeof(buf), "AsyncSQL::DirectQuery : mysql_query error: %s\nquery: %s", mysql_error (&m_hDB), p->stQuery.c_str());
sys_err (buf);
p->uiSQLErrno = mysql_errno (&m_hDB);
}
p->Store();
return p;
}
void CAsyncSQL::AsyncQuery (const char* c_pszQuery)
{
auto p = new SQLMsg;
p->m_pkSQL = &m_hDB;
p->iID = ++m_iMsgCount;
p->stQuery = c_pszQuery;
PushQuery (p);
}
void CAsyncSQL::ReturnQuery (const char* c_pszQuery, void* pvUserData)
{
auto p = new SQLMsg;
p->m_pkSQL = &m_hDB;
p->iID = ++m_iMsgCount;
p->stQuery = c_pszQuery;
p->bReturn = true;
p->pvUserData = pvUserData;
PushQuery (p);
}
void CAsyncSQL::PushResult (SQLMsg* p)
{
MUTEX_LOCK (m_mtxResult);
m_queue_result.push (p);
MUTEX_UNLOCK (m_mtxResult);
}
bool CAsyncSQL::PopResult(SQLMsg** pp)
{
MUTEX_LOCK (m_mtxResult);
if (m_queue_result.empty())
{
MUTEX_UNLOCK (m_mtxResult);
return false;
}
*pp = m_queue_result.front();
m_queue_result.pop();
MUTEX_UNLOCK (m_mtxResult);
return true;
}
void CAsyncSQL::PushQuery (SQLMsg* p)
{
MUTEX_LOCK (m_mtxQuery);
m_queue_query.push (p);
m_sem.Release();
MUTEX_UNLOCK (m_mtxQuery);
}
bool CAsyncSQL::PeekQuery (SQLMsg** pp)
{
MUTEX_LOCK (m_mtxQuery);
if (m_queue_query.empty())
{
MUTEX_UNLOCK (m_mtxQuery);
return false;
}
*pp = m_queue_query.front();
MUTEX_UNLOCK (m_mtxQuery);
return true;
}
bool CAsyncSQL::PopQuery (int iID)
{
MUTEX_LOCK (m_mtxQuery);
if (m_queue_query.empty())
{
MUTEX_UNLOCK (m_mtxQuery);
return false;
}
m_queue_query.pop();
MUTEX_UNLOCK (m_mtxQuery);
return true;
}
bool CAsyncSQL::PeekQueryFromCopyQueue (SQLMsg** pp)
{
if (m_queue_query_copy.empty())
{
return false;
}
*pp = m_queue_query_copy.front();
return true;
}
int CAsyncSQL::CopyQuery()
{
MUTEX_LOCK (m_mtxQuery);
if (m_queue_query.empty())
{
MUTEX_UNLOCK (m_mtxQuery);
return -1;
}
while (!m_queue_query.empty())
{
SQLMsg* p = m_queue_query.front();
m_queue_query_copy.push (p);
m_queue_query.pop();
}
int count = m_queue_query_copy.size();
MUTEX_UNLOCK (m_mtxQuery);
return count;
}
bool CAsyncSQL::PopQueryFromCopyQueue()
{
if (m_queue_query_copy.empty())
{
return false;
}
m_queue_query_copy.pop();
return true;
}
int CAsyncSQL::GetCopiedQueryCount()
{
return m_iCopiedQuery;
}
void CAsyncSQL::ResetCopiedQueryCount()
{
m_iCopiedQuery = 0;
}
void CAsyncSQL::AddCopiedQueryCount (int iCopiedQuery)
{
m_iCopiedQuery += iCopiedQuery;
}
DWORD CAsyncSQL::CountQuery()
{
return m_queue_query.size();
}
DWORD CAsyncSQL::CountResult()
{
return m_queue_result.size();
}
void __timediff (struct timeval* a, struct timeval* b, struct timeval* rslt)
{
if (a->tv_sec < b->tv_sec)
{
rslt->tv_sec = rslt->tv_usec = 0;
}
else if (a->tv_sec == b->tv_sec)
{
if (a->tv_usec < b->tv_usec)
{
rslt->tv_sec = rslt->tv_usec = 0;
}
else
{
rslt->tv_sec = 0;
rslt->tv_usec = a->tv_usec - b->tv_usec;
}
}
else
{
rslt->tv_sec = a->tv_sec - b->tv_sec;
if (a->tv_usec < b->tv_usec)
{
rslt->tv_usec = a->tv_usec + 1000000 - b->tv_usec;
rslt->tv_sec--;
}
else
{
rslt->tv_usec = a->tv_usec - b->tv_usec;
}
}
}
class cProfiler
{
public:
cProfiler()
{
m_nInterval = 0 ;
memset (&prev, 0, sizeof (prev));
memset (&now, 0, sizeof (now));
memset (&interval, 0, sizeof (interval));
Start();
}
cProfiler (int nInterval = 100000)
{
m_nInterval = nInterval;
memset (&prev, 0, sizeof (prev));
memset (&now, 0, sizeof (now));
memset (&interval, 0, sizeof (interval));
Start();
}
void Start()
{
gettimeofday (&prev , (struct timezone*) 0);
}
void Stop()
{
gettimeofday (&now, (struct timezone*) 0);
__timediff (&now, &prev, &interval);
}
bool IsOk()
{
if (interval.tv_sec > (m_nInterval / 1000000))
{
return false;
}
if (interval.tv_usec > m_nInterval)
{
return false;
}
return true;
}
struct timeval* GetResult()
{
return &interval;
}
long GetResultSec()
{
return interval.tv_sec;
}
long GetResultUSec()
{
return interval.tv_usec;
}
private:
int m_nInterval;
struct timeval prev;
struct timeval now;
struct timeval interval;
};
void CAsyncSQL::ChildLoop()
{
cProfiler profiler(500000);
while (!m_bEnd)
{
m_sem.Wait();
int count = CopyQuery();
if (count <= 0)
{
continue;
}
AddCopiedQueryCount (count);
SQLMsg* p;
while (count--)
{
profiler.Start();
if (!PeekQueryFromCopyQueue (&p))
{
continue;
}
if (m_ulThreadID != mysql_thread_id (&m_hDB))
{
sys_log (0, "MySQL connection was reconnected. querying locale set");
while (!QueryLocaleSet());
m_ulThreadID = mysql_thread_id (&m_hDB);
}
if (mysql_real_query (&m_hDB, p->stQuery.c_str(), p->stQuery.length()))
{
p->uiSQLErrno = mysql_errno (&m_hDB);
sys_err ("AsyncSQL: query failed: %s (query: %s errno: %d)", mysql_error (&m_hDB), p->stQuery.c_str(), p->uiSQLErrno);
switch (p->uiSQLErrno)
{
case CR_SOCKET_CREATE_ERROR:
case CR_CONNECTION_ERROR:
case CR_IPSOCK_ERROR:
case CR_UNKNOWN_HOST:
case CR_SERVER_GONE_ERROR:
case CR_CONN_HOST_ERROR:
case ER_NOT_KEYFILE:
case ER_CRASHED_ON_USAGE:
case ER_CANT_OPEN_FILE:
case ER_HOST_NOT_PRIVILEGED:
case ER_HOST_IS_BLOCKED:
case ER_PASSWORD_NOT_ALLOWED:
case ER_PASSWORD_NO_MATCH:
case ER_CANT_CREATE_THREAD:
case ER_INVALID_USE_OF_NULL:
m_sem.Release();
sys_err ("AsyncSQL: retrying");
continue;
}
}
profiler.Stop();
if (!profiler.IsOk())
{
sys_log (0, "[QUERY : LONG INTERVAL(OverSec %ld.%ld)] : %s", profiler.GetResultSec(), profiler.GetResultUSec(), p->stQuery.c_str());
}
PopQueryFromCopyQueue();
if (p->bReturn)
{
p->Store();
PushResult (p);
}
else
{
delete p;
}
++m_iQueryFinished;
}
}
SQLMsg* p;
while (PeekQuery (&p))
{
if (m_ulThreadID != mysql_thread_id (&m_hDB))
{
sys_log (0, "MySQL connection was reconnected. querying locale set");
while (!QueryLocaleSet());
m_ulThreadID = mysql_thread_id (&m_hDB);
}
if (mysql_real_query (&m_hDB, p->stQuery.c_str(), p->stQuery.length()))
{
p->uiSQLErrno = mysql_errno (&m_hDB);
sys_err ("AsyncSQL::ChildLoop : mysql_query error: %s:\nquery: %s", mysql_error (&m_hDB), p->stQuery.c_str());
switch (p->uiSQLErrno)
{
case CR_SOCKET_CREATE_ERROR:
case CR_CONNECTION_ERROR:
case CR_IPSOCK_ERROR:
case CR_UNKNOWN_HOST:
case CR_SERVER_GONE_ERROR:
case CR_CONN_HOST_ERROR:
case ER_NOT_KEYFILE:
case ER_CRASHED_ON_USAGE:
case ER_CANT_OPEN_FILE:
case ER_HOST_NOT_PRIVILEGED:
case ER_HOST_IS_BLOCKED:
case ER_PASSWORD_NOT_ALLOWED:
case ER_PASSWORD_NO_MATCH:
case ER_CANT_CREATE_THREAD:
case ER_INVALID_USE_OF_NULL:
continue;
}
}
sys_log (0, "QUERY_FLUSH: %s", p->stQuery.c_str());
PopQuery (p->iID);
if (p->bReturn)
{
p->Store();
PushResult (p);
}
else
{
delete p;
}
++m_iQueryFinished;
}
}
int CAsyncSQL::CountQueryFinished()
{
return m_iQueryFinished;
}
void CAsyncSQL::ResetQueryFinished()
{
m_iQueryFinished = 0;
}
MYSQL* CAsyncSQL::GetSQLHandle()
{
return &m_hDB;
}
size_t CAsyncSQL::EscapeString (char* dst, size_t dstSize, const char* src, size_t srcSize)
{
if (0 == srcSize)
{
memset (dst, 0, dstSize);
return 0;
}
if (0 == dstSize)
{
return 0;
}
if (dstSize < srcSize * 2 + 1)
{
char tmp[256];
size_t tmpLen = sizeof (tmp) > srcSize ? srcSize : sizeof (tmp);
strlcpy (tmp, src, tmpLen);
sys_err ("FATAL ERROR!! not enough buffer size (dstSize %u srcSize %u src%s: %s)", dstSize, srcSize, tmpLen != srcSize ? "(trimmed to 255 characters)" : "", tmp);
dst[0] = '\0';
return 0;
}
return mysql_real_escape_string (GetSQLHandle(), dst, src, srcSize);
}
void CAsyncSQL2::SetLocale (const std::string & stLocale)
{
m_stLocale = stLocale;
QueryLocaleSet();
}
This is my AsyncSQL.h
#ifndef __INC_METIN_II_ASYNCSQL_H__
#define __INC_METIN_II_ASYNCSQL_H__
#include "../../libthecore/src/stdafx.h"
#include "../../libthecore/src/log.h"
#include "../../Ayarlar.h"
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <mysql/server/mysql.h>
#include <mysql/server/errmsg.h>
#include <mysql/server/mysqld_error.h>
#include "Semaphore.h"
typedef struct _SQLResult
{
_SQLResult(): pSQLResult (NULL), uiNumRows (0), uiAffectedRows (0), uiInsertID (0) {}
~_SQLResult()
{
if (pSQLResult)
{
mysql_free_result (pSQLResult);
pSQLResult = NULL;
}
}
MYSQL_RES* pSQLResult;
uint32_t uiNumRows;
uint32_t uiAffectedRows;
uint32_t uiInsertID;
} SQLResult;
typedef struct _SQLMsg
{
_SQLMsg() : m_pkSQL (NULL), iID (0), uiResultPos (0), pvUserData (NULL), bReturn (false), uiSQLErrno (0) {}
~_SQLMsg()
{
auto first = vec_pkResult.begin();
auto past = vec_pkResult.end();
while (first != past)
{
delete * (first++);
}
vec_pkResult.clear();
}
void Store()
{
do
{
SQLResult* pRes = new SQLResult;
pRes->pSQLResult = mysql_store_result (m_pkSQL);
pRes->uiInsertID = mysql_insert_id (m_pkSQL);
pRes->uiAffectedRows = mysql_affected_rows (m_pkSQL);
if (pRes->pSQLResult)
{
pRes->uiNumRows = mysql_num_rows (pRes->pSQLResult);
}
else
{
pRes->uiNumRows = 0;
}
vec_pkResult.push_back (pRes);
}
while (!mysql_next_result (m_pkSQL));
}
SQLResult* Get()
{
if (uiResultPos >= vec_pkResult.size())
{
return NULL;
}
return vec_pkResult[uiResultPos];
}
bool Next()
{
if (uiResultPos + 1 >= vec_pkResult.size())
{
return false;
}
++uiResultPos;
return true;
}
MYSQL* m_pkSQL;
int iID;
std::string stQuery;
std::vector<SQLResult *> vec_pkResult;
unsigned int uiResultPos;
void* pvUserData;
bool bReturn;
unsigned int uiSQLErrno;
} SQLMsg;
class CAsyncSQL
{
public:
CAsyncSQL();
virtual ~CAsyncSQL();
void Quit();
bool Setup (const char* c_pszHost, const char* c_pszUser, const char* c_pszPassword, const char* c_pszDB, const char* c_pszLocale, bool bNoThread = false, int iPort = 0);
bool Setup (CAsyncSQL* sql, bool bNoThread = false);
bool Connect();
bool IsConnected()
{
return m_bConnected;
}
bool QueryLocaleSet();
void AsyncQuery (const char* c_pszQuery);
void ReturnQuery (const char* c_pszQuery, void* pvUserData);
SQLMsg* DirectQuery (const char* c_pszQuery);
DWORD CountQuery();
DWORD CountResult();
void PushResult (SQLMsg* p);
bool PopResult (SQLMsg** pp);
void ChildLoop();
MYSQL* GetSQLHandle();
int CountQueryFinished();
void ResetQueryFinished();
size_t EscapeString (char* dst, size_t dstSize, const char* src, size_t srcSize);
protected:
void Destroy();
void PushQuery (SQLMsg* p);
bool PeekQuery (SQLMsg** pp);
bool PopQuery (int iID);
bool PeekQueryFromCopyQueue (SQLMsg** pp );
INT CopyQuery();
bool PopQueryFromCopyQueue();
public:
int GetCopiedQueryCount();
void ResetCopiedQueryCount();
void AddCopiedQueryCount (int iCopiedQuery);
protected:
MYSQL m_hDB;
std::string m_stHost;
std::string m_stUser;
std::string m_stPassword;
std::string m_stDB;
std::string m_stLocale;
int m_iMsgCount;
int m_aiPipe[2];
int m_iPort;
std::queue<SQLMsg*> m_queue_query;
std::queue<SQLMsg*> m_queue_query_copy;
std::queue<SQLMsg*> m_queue_result;
volatile bool m_bEnd;
pthread_t m_hThread;
pthread_mutex_t* m_mtxQuery;
pthread_mutex_t* m_mtxResult;
CSemaphore m_sem;
int m_iQueryFinished;
unsigned long m_ulThreadID;
bool m_bConnected;
int m_iCopiedQuery;
};
class CAsyncSQL2 : public CAsyncSQL
{
public:
void SetLocale (const std::string & stLocale);
};
#endif
And this is the function the reason of the error ;
optional:1052 ;
#ifdef __cpp_lib_three_way_comparison
template<typename _Tp>
constexpr strong_ordering
operator<=>(const optional<_Tp>& __x, nullopt_t) noexcept
{ return bool(__x) <=> false; }
#else
After a see a document the microsoft release i'm gonna try <= > false; like this and take a error again..
Best Regards.
I ve no idea why it looks is getting bool(__x) <=> false as an bool and int comparison.
I would think you got some strange macro in your files included before to include the header that is going to break the standard code.
I would suggest you try to move above the standard headers and below them your 'user defined' headers.
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <mysql/server/mysql.h>
#include <mysql/server/errmsg.h>
#include <mysql/server/mysqld_error.h>
#include "../../libthecore/src/stdafx.h"
#include "../../libthecore/src/log.h"
#include "../../Ayarlar.h"
#include "Semaphore.h"
EDIT:
i ve found the cause of the problem.
a macro defined in "libthrecore/stdafx.h" (i own the files that is using the author, they are public).
#ifndef false
#define false 0
#define true (!false)
#endif
it is causing false to be read as a int and is causing the spaceship operator to fails with the error shown by the author. Move up the standard headers or remove the macro to solve the error.
I'm trying to add Nvidia API into kodi for HDR switching.
I don't have much knowledge of code, I'm trying to adapt a project HDR Switcher into kodi functions.
When compiling the HDR Switcher into an exe with visual studio it works and triggers HDR.
Now I need to make it work with kodi for seamless HDR pasthrough playback.
This uses the NVidia private APIs.
Please help this will be valuable for many users if it gets implemented.
The error:
error C2664: 'NvAPI_St
atus NvAPI_GPU_GetConnectedDisplayIds(NvPhysicalGpuHandle,NV_GPU_DISPLAYIDS *,NvU32 *,NvU32)': cannot convert argument
1 from 'NvPhysicalGpuHandle [64]' to 'NvPhysicalGpuHandle'
#include "WinRenderer.h"
#include "RenderCapture.h"
#include "RenderFactory.h"
#include "RenderFlags.h"
#include "rendering/dx/RenderContext.h"
#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
#include "utils/log.h"
#include "windows/RendererDXVA.h"
#include "windows/RendererSoftware.h"
#include "windows/RendererShaders.h"
#include "windowing/GraphicContext.h"
#include "windowing/WinSystem.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include "DeviceManager.h"
#include "nvapi.h"
#include "uhdDisplay.h"
struct render_details
{
using map = std::map<RenderMethod, int>;
using weights_fn = std::function<void(map&, const VideoPicture&)>;
using create_fn = std::function<CRendererBase*(CVideoSettings&)>;
RenderMethod method;
std::string name;
create_fn create;
weights_fn weights;
template<class T>
constexpr static render_details get(RenderMethod method, const std::string& name)
{
return { method, name, T::Create, T::GetWeight };
}
};
static std::vector<render_details> RenderMethodDetails =
{
render_details::get<CRendererSoftware>(RENDER_SW, "Software"),
render_details::get<CRendererShaders>(RENDER_PS, "Pixel Shaders"),
render_details::get<CRendererDXVA>(RENDER_DXVA, "DXVA"),
};
CBaseRenderer* CWinRenderer::Create(CVideoBuffer*)
{
return new CWinRenderer();
}
bool CWinRenderer::Register()
{
VIDEOPLAYER::CRendererFactory::RegisterRenderer("default", Create);
return true;
}
CWinRenderer::CWinRenderer()
{
m_format = AV_PIX_FMT_NONE;
PreInit();
}
CWinRenderer::~CWinRenderer()
{
CWinRenderer::UnInit();
}
CRendererBase* CWinRenderer::SelectRenderer(const VideoPicture& picture)
{
int iRequestedMethod = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_RENDERMETHOD);
CLog::LogF(LOGDEBUG, "requested render method: %d", iRequestedMethod);
std::map<RenderMethod, int> weights;
for (auto& details : RenderMethodDetails)
details.weights(weights, picture);
RenderMethod method;
switch (iRequestedMethod)
{
case RENDER_METHOD_SOFTWARE:
if (weights[RENDER_SW])
{
method = RENDER_SW;
break;
}
// fallback to PS
case RENDER_METHOD_D3D_PS:
if (weights[RENDER_PS])
{
method = RENDER_PS;
break;
}
//fallback to DXVA
case RENDER_METHOD_DXVA:
if (weights[RENDER_DXVA])
{
method = RENDER_DXVA;
break;
}
// fallback to AUTO
case RENDER_METHOD_AUTO:
default:
{
const auto it = std::max_element(weights.begin(), weights.end(),
[](auto& w1, auto& w2) { return w1.second < w2.second; });
if (it != weights.end())
{
method = it->first;
break;
}
// there is no elements in weights, so no renderer which supports incoming video buffer
CLog::LogF(LOGERROR, "unable to select render method for video buffer");
return nullptr;
}
}
const auto it = std::find_if(RenderMethodDetails.begin(), RenderMethodDetails.end(),
[method](render_details& d) { return d.method == method; });
if (it != RenderMethodDetails.end())
{
CLog::LogF(LOGDEBUG, "selected render method: {}", it->name);
return it->create(m_videoSettings);
}
// something goes really wrong
return nullptr;
}
CRect CWinRenderer::GetScreenRect() const
{
CRect screenRect(0.f, 0.f,
static_cast<float>(CServiceBroker::GetWinSystem()->GetGfxContext().GetWidth()),
static_cast<float>(CServiceBroker::GetWinSystem()->GetGfxContext().GetHeight()));
switch (CServiceBroker::GetWinSystem()->GetGfxContext().GetStereoMode())
{
case RENDER_STEREO_MODE_SPLIT_HORIZONTAL:
screenRect.y2 *= 2;
break;
case RENDER_STEREO_MODE_SPLIT_VERTICAL:
screenRect.x2 *= 2;
break;
default:
break;
}
return screenRect;
}
bool CWinRenderer::Configure(const VideoPicture &picture, float fps, unsigned int orientation)
{
m_sourceWidth = picture.iWidth;
m_sourceHeight = picture.iHeight;
m_renderOrientation = orientation;
m_fps = fps;
m_iFlags = GetFlagsChromaPosition(picture.chroma_position)
| GetFlagsColorMatrix(picture.color_space, picture.iWidth, picture.iHeight)
| GetFlagsColorPrimaries(picture.color_primaries)
| GetFlagsStereoMode(picture.stereoMode);
m_format = picture.videoBuffer->GetFormat();
// calculate the input frame aspect ratio
CalculateFrameAspectRatio(picture.iDisplayWidth, picture.iDisplayHeight);
SetViewMode(m_videoSettings.m_ViewMode);
// if (picture.hasDisplayMetadata || picture.hasLightMetadata) {
SetHdrMonitorMode(true);
// }
ManageRenderArea();
m_renderer.reset(SelectRenderer(picture));
if (!m_renderer || !m_renderer->Configure(picture, fps, orientation))
{
m_renderer.reset();
return false;
}
m_bConfigured = true;
return true;
}
static bool first = true;
void CWinRenderer::SetHdrMonitorMode(bool enableHDR)
{
if (first)
{
NvAPI_Initialize();
first = false;
}
NvAPI_Status nvStatus = NVAPI_OK;
NvDisplayHandle hNvDisplay = NULL;
// get first display handle which should work for all NVAPI calls for all GPUs
if ((nvStatus = NvAPI_EnumNvidiaDisplayHandle(0, &hNvDisplay)) != NVAPI_OK)
{
printf("NvAPI_EnumNvidiaDisplayHandle returned error code %d\r\n", nvStatus);
return;
}
NvU32 gpuCount = 0;
NvU32 maxDisplayIndex = 0;
NvPhysicalGpuHandle ahGPU[NVAPI_MAX_PHYSICAL_GPUS] = {};
// get the list of displays connected, populate the dynamic components
nvStatus = NvAPI_EnumPhysicalGPUs(ahGPU, &gpuCount);
if (NVAPI_OK != nvStatus)
{
printf("NvAPI_EnumPhysicalGPUs returned error code %d\r\n", nvStatus);
return;
}
for (NvU32 i = 0; i < gpuCount; ++i)
{
NvU32 displayIdCount = 16;
NvU32 flags = 0;
NV_GPU_DISPLAYIDS displayIdArray[16] = {};
displayIdArray[0].version = NV_GPU_DISPLAYIDS_VER;
nvStatus = NvAPI_GPU_GetConnectedDisplayIds(ahGPU, displayIdArray, &displayIdCount, flags);
if (NVAPI_OK == nvStatus)
{
printf("Display count %d\r\n", displayIdCount);
for (maxDisplayIndex = 0; maxDisplayIndex < displayIdCount; ++maxDisplayIndex)
{
printf("Display tested %d\r\n", maxDisplayIndex);
NV_HDR_CAPABILITIES hdrCapabilities = {};
hdrCapabilities.version = NV_HDR_CAPABILITIES_VER;
if (NVAPI_OK == NvAPI_Disp_GetHdrCapabilities(displayIdArray[maxDisplayIndex].displayId, &hdrCapabilities))
{
if (hdrCapabilities.isST2084EotfSupported)
{
printf("Display %d supports ST2084 EOTF\r\n", maxDisplayIndex);
NV_HDR_COLOR_DATA hdrColorData = {};
memset(&hdrColorData, 0, sizeof(hdrColorData));
hdrColorData.version = NV_HDR_COLOR_DATA_VER;
hdrColorData.cmd = NV_HDR_CMD_SET;
hdrColorData.static_metadata_descriptor_id = NV_STATIC_METADATA_TYPE_1;
hdrColorData.hdrMode = enableHDR ? NV_HDR_MODE_UHDBD : NV_HDR_MODE_OFF;
nvStatus = NvAPI_Disp_HdrColorControl(displayIdArray[maxDisplayIndex].displayId, &hdrColorData);
if (NVAPI_OK == nvStatus)
{
printf("NvAPI_Disp_SethdrColorData call has succeeded: ");
}
else
{
NvAPI_ShortString szDesc;
NvAPI_GetErrorMessage(nvStatus, szDesc);
printf("NvAPI_Disp_HdrColorControl returned %s (%x)\r\n", szDesc, nvStatus);
}
}
}
else
{
NvAPI_ShortString szDesc;
NvAPI_GetErrorMessage(nvStatus, szDesc);
printf("NvAPI_Disp_GetHdrCapabilities returned %s (%x)\r\n", szDesc, nvStatus);
}
}
}
else
{
NvAPI_ShortString szDesc;
NvAPI_GetErrorMessage(nvStatus, szDesc);
printf("NvAPI_GPU_GetConnectedDisplayIds returned %s (%x)\r\n", szDesc, nvStatus);
}
}
}
int CWinRenderer::NextBuffer() const
{
return m_renderer->NextBuffer();
}
void CWinRenderer::AddVideoPicture(const VideoPicture &picture, int index)
{
m_renderer->AddVideoPicture(picture, index);
}
void CWinRenderer::Update()
{
if (!m_bConfigured)
return;
ManageRenderArea();
m_renderer->ManageTextures();
}
void CWinRenderer::RenderUpdate(int index, int index2, bool clear, unsigned int flags, unsigned int alpha)
{
if (!m_bConfigured)
return;
if (clear)
CServiceBroker::GetWinSystem()->GetGfxContext().Clear(DX::Windowing()->UseLimitedColor() ? 0x101010 : 0);
DX::Windowing()->SetAlphaBlendEnable(alpha < 255);
ManageRenderArea();
m_renderer->Render(index, index2, DX::Windowing()->GetBackBuffer(),
m_sourceRect, m_destRect, GetScreenRect(), flags);
}
bool CWinRenderer::RenderCapture(CRenderCapture* capture)
{
if (!m_bConfigured)
return false;
capture->BeginRender();
if (capture->GetState() != CAPTURESTATE_FAILED)
{
const CRect destRect(0, 0, static_cast<float>(capture->GetWidth()), static_cast<float>(capture->GetHeight()));
m_renderer->Render(capture->GetTarget(), m_sourceRect, destRect, GetScreenRect());
capture->EndRender();
return true;
}
return false;
}
void CWinRenderer::SetBufferSize(int numBuffers)
{
if (!m_bConfigured)
return;
m_renderer->SetBufferSize(numBuffers);
}
void CWinRenderer::PreInit()
{
CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
m_bConfigured = false;
UnInit();
}
void CWinRenderer::UnInit()
{
CSingleLock lock(CServiceBroker::GetWinSystem()->GetGfxContext());
m_renderer.reset();
m_bConfigured = false;
}
bool CWinRenderer::Flush(bool saveBuffers)
{
if (!m_bConfigured)
return false;
return m_renderer->Flush(saveBuffers);
}
bool CWinRenderer::Supports(ERENDERFEATURE feature)
{
if(feature == RENDERFEATURE_BRIGHTNESS)
return true;
if(feature == RENDERFEATURE_CONTRAST)
return true;
if (feature == RENDERFEATURE_STRETCH ||
feature == RENDERFEATURE_NONLINSTRETCH ||
feature == RENDERFEATURE_ZOOM ||
feature == RENDERFEATURE_VERTICAL_SHIFT ||
feature == RENDERFEATURE_PIXEL_RATIO ||
feature == RENDERFEATURE_ROTATION ||
feature == RENDERFEATURE_POSTPROCESS ||
feature == RENDERFEATURE_TONEMAP)
return true;
return false;
}
bool CWinRenderer::Supports(ESCALINGMETHOD method)
{
if (!m_bConfigured)
return false;
return m_renderer->Supports(method);
}
bool CWinRenderer::WantsDoublePass()
{
if (!m_bConfigured)
return false;
return m_renderer->WantsDoublePass();
}
bool CWinRenderer::ConfigChanged(const VideoPicture& picture)
{
if (!m_bConfigured)
return true;
return picture.videoBuffer->GetFormat() != m_format;
}
CRenderInfo CWinRenderer::GetRenderInfo()
{
if (!m_bConfigured)
return {};
return m_renderer->GetRenderInfo();
}
void CWinRenderer::ReleaseBuffer(int idx)
{
if (!m_bConfigured)
return;
m_renderer->ReleaseBuffer(idx);
}
bool CWinRenderer::NeedBuffer(int idx)
{
if (!m_bConfigured)
return false;
return m_renderer->NeedBuffer(idx);
}
ยดยดยด
Change
nvStatus = NvAPI_GPU_GetConnectedDisplayIds(ahGPU, displayIdArray, &displayIdCount, flags);
to
nvStatus = NvAPI_GPU_GetConnectedDisplayIds(ahGPU[i], displayIdArray, &displayIdCount, flags);
Thanks to #1201ProgramAlarm
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I am converting our code to use IOCP and I got the communication relatively stable, but the memory usage of the application is increasing. Looks like I am getting back (on completion function calls) much fewer objects of OverlappedEx than I create. My code is below. What am I doing wrong?
#ifndef NETWORK_DATA
#define NETWORK_DATA
#include <afxwin.h>
#include <vector>
#include <string>
#include "CriticalSectionLocker.h"
using namespace std;
DWORD NetworkManager::NetworkThread(void* param)
{
bool bRun = true;
while (bRun)
{
DWORD wait = ::WaitForSingleObject(CCommunicationManager::s_hShutdownEvent, 0);
if (WAIT_OBJECT_0 == wait)
{
bRun = false;
DEBUG_LOG0("Shutdown event was signalled thread");
}
else
{
DWORD dwBytesTransfered = 0;
void* lpContext = nullptr;
OVERLAPPED* pOverlapped = nullptr;
BOOL bReturn = GetQueuedCompletionStatus(s_IOCompletionPort,
&dwBytesTransfered,
(LPDWORD)&lpContext,
&pOverlapped,
INFINITE);
if (nullptr == lpContext)
{
DEBUG_LOG0("invalid context");
/*continue;*/
}
else
{
if (bReturn && dwBytesTransfered > 0)
{
OverlappedEx* data = reinterpret_cast<OverlappedEx*>(pOverlapped);
ServerData* networkData = reinterpret_cast<ServerData*>(lpContext);
if (networkData && data)
{
switch(data->m_opType)
{
case OverlappedEx::OP_READ:
/*DEBUG_LOG4("device name: %s bytes received: %d socket: %d handle: %d",
networkData->Name().c_str(), dwBytesTransfered, networkData->Socket(), networkData->Handle());*/
networkData->CompleteReceive(dwBytesTransfered, data);
break;
case OverlappedEx::OP_WRITE:
/*DEBUG_LOG4("device name: %s bytes sent: %d socket: %d handle: %d",
networkData->Name().c_str(), dwBytesTransfered, networkData->Socket(), networkData->Handle());*/
networkData->CompleteSend(dwBytesTransfered, data);
break;
}
}
}
else
{
/*DEBUG_LOG2("GetQueuedCompletionStatus failed: bReturn: %d dwBytesTransferred: %u", bReturn, dwBytesTransfered);*/
}
}
}
}
return 0;
}
enum NetworkType
{
UDP,
TCP
};
struct OverlappedEx : public OVERLAPPED
{
enum OperationType
{
OP_READ,
OP_WRITE
};
const static int MAX_PACKET_SIZE = 2048;
WSABUF m_wBuf;
char m_buffer[MAX_PACKET_SIZE];
OperationType m_opType;
OverlappedEx()
{
Clear();
m_refCount = 1;
}
void AddRef()
{
::InterlockedIncrement(&m_refCount);
}
void Release()
{
::InterlockedDecrement(&m_refCount);
}
int Refcount() const
{
return InterlockedExchangeAdd((unsigned long*)&m_refCount, 0UL);
}
~OverlappedEx()
{
Clear();
}
void Clear()
{
memset(m_buffer, 0, MAX_PACKET_SIZE);
m_wBuf.buf = m_buffer;
m_wBuf.len = MAX_PACKET_SIZE;
Internal = 0;
InternalHigh = 0;
Offset = 0;
OffsetHigh = 0;
hEvent = nullptr;
m_opType = OP_READ;
}
private:
volatile LONG m_refCount;
};
class ServerData
{
public:
const static int MAX_REVEIVE_QUEUE_SIZE = 100;
const static int MAX_PACKET_SIZE = 2048;
const static int MAX_SEND_QUEUE_SIZE = 10;
const static int MAX_RECEIVE_QUEUE_SIZE = 100;
const static int MAX_OVERLAPPED_STRUCTS = 20;
ServerData(NetworkType netType, const string& sName, CCommunicationManager::CommHandle handle,
SOCKET sock, HANDLE IOPort) :
m_sName(sName)
{
InitializeCriticalSection(&m_receiveQueLock);
InitializeCriticalSection(&m_objectLock);
m_Handle = handle;
m_Socket = sock;
m_nIPAddress = 0;
m_netType = netType;
m_bEnabled = true;
m_ovlpIndex = 0;
for (int i = 0; i < MAX_OVERLAPPED_STRUCTS; ++i)
{
m_olps.push_back(new OverlappedEx);
}
/* Associate socket with completion handle */
if (m_Socket != 0)
{
CreateIoCompletionPort( reinterpret_cast<HANDLE>(m_Socket), IOPort, reinterpret_cast<ULONG_PTR>(this), 0 );
}
}
~ServerData()
{
CriticalSectionLocker lock(&m_receiveQueLock);
DeleteCriticalSection(&m_receiveQueLock);
DeleteCriticalSection(&m_objectLock);
closesocket(m_Socket);
}
const string& Name() const { return m_sName; }
bool Enabled() const { return m_bEnabled; }
void SetEnabled(bool bEnabled)
{
m_bEnabled = bEnabled;
}
int Handle() const { return m_Handle; }
void SetHandle(int handle)
{
m_Handle = handle;
}
unsigned long IPAddress() const { return m_nIPAddress; }
SOCKET Socket() const
{
return m_Socket;
}
void SetSocket(SOCKET sock)
{
m_Socket = sock;
}
void SetIPAddress(unsigned long nIP)
{
m_nIPAddress = nIP;
}
bool ValidTelegram(const vector<char>& telegram) const
{
return false;
}
OverlappedEx* GetBuffer()
{
OverlappedEx* ret = nullptr;
if (!m_olps.empty())
{
ret = m_olps.front();
m_olps.pop_front();
}
return ret;
}
void CompleteReceive(size_t numBytes, OverlappedEx* data)
{
//DEBUG_LOG1("%d buffers are available", AvailableBufferCount());
if (numBytes > 0)
{
vector<char> v(data->m_buffer, data->m_buffer + numBytes);
ReceivedData rd;
rd.SetData(v);
EnqueReceiveMessage(rd);
}
data->Release();
{
CriticalSectionLocker lock(&m_objectLock);
m_olps.push_back(data);
// DEBUG_LOG1("Queue size: %d", m_olps.size());
}
StartReceiving();
}
void CompleteSend(size_t numBytes, OverlappedEx* data)
{
data->Release();
{
CriticalSectionLocker lock(&m_objectLock);
m_olps.push_back(data);
//DEBUG_LOG1("Queue size: %d", m_olps.size());
}
//DEBUG_LOG2("Object: %s num sent: %d", Name().c_str(), numBytes);
}
void StartReceiving()
{
DWORD bytesRecv = 0;
sockaddr_in senderAddr;
DWORD flags = 0;
int senderAddrSize = sizeof(senderAddr);
int rc = 0;
CriticalSectionLocker lock(&m_objectLock);
auto olp = GetBuffer();
if (!olp)
{
if (...)
{
m_olps.push_back(new OverlappedEx);
olp = GetBuffer();
}
else
{
if (...)
{
DEBUG_LOG1("Name: %s ************* NO AVAILABLE BUFFERS - bailing ***************", Name().c_str());
}
return;
}
}
olp->Clear();
olp->m_opType = OverlappedEx::OP_READ;
olp->AddRef();
switch(GetNetworkType())
{
case UDP:
{
rc = WSARecvFrom(Socket(),
&olp->m_wBuf,
1,
&bytesRecv,
&flags,
(SOCKADDR *)&senderAddr,
&senderAddrSize, (OVERLAPPED*)olp, NULL);
}
break;
case TCP:
{
rc = WSARecv(Socket(),
&olp->m_wBuf,
1,
&bytesRecv,
&flags,
(OVERLAPPED*)olp, NULL);
}
break;
}
if (SOCKET_ERROR == rc)
{
DWORD err = WSAGetLastError();
if (err != WSA_IO_PENDING)
{
olp->Release();
m_olps.push_back(olp);
}
}
}
void SetWriteBuf(const SendData& msg, OverlappedEx* data)
{
int len = min(msg.Data().size(), MAX_PACKET_SIZE);
memcpy(data->m_buffer, &msg.Data()[0], len);
data->m_wBuf.buf = data->m_buffer;
data->m_wBuf.len = len;
}
void StartSending(const SendData& msg)
{
DEBUG_LOG1("device name: %s", Name().c_str());
int rc = 0;
DWORD bytesSent = 0;
DWORD flags = 0;
SOCKET sock = Socket();
int addrSize = sizeof(sockaddr_in);
CriticalSectionLocker lock(&m_objectLock);
//UpdateOverlapped(OverlappedEx::OP_WRITE);
auto olp = GetBuffer();
if (!olp)
{
if (...)
{
m_olps.push_back(new OverlappedEx);
olp = GetBuffer();
DEBUG_LOG2("name: %s ************* NO AVAILABLE BUFFERS new size: %d ***************", Name().c_str(), m_olps.size());
}
else
{
if (...)
{
DEBUG_LOG1("Name: %s ************* NO AVAILABLE BUFFERS - bailing ***************", Name().c_str());
}
return;
}
}
olp->Clear();
olp->m_opType = OverlappedEx::OP_WRITE;
olp->AddRef();
SetWriteBuf(msg, olp);
switch(GetNetworkType())
{
case UDP:
rc = WSASendTo(Socket(), &olp->m_wBuf, 1,
&bytesSent, flags, (sockaddr*)&msg.SendAddress(),
addrSize, (OVERLAPPED*)olp, NULL);
break;
case TCP:
rc = WSASend(Socket(), &olp->m_wBuf, 1,
&bytesSent, flags, (OVERLAPPED*)olp, NULL);
break;
}
if (SOCKET_ERROR == rc)
{
DWORD err = WSAGetLastError();
if (err != WSA_IO_PENDING)
{
olp->Release();
m_olps.push_back(olp);
}
}
}
size_t ReceiveQueueSize()
{
CriticalSectionLocker lock(&m_receiveQueLock);
return m_receiveDataQueue.size();
}
void GetAllData(vector <ReceivedData> & data)
{
CriticalSectionLocker lock(&m_receiveQueLock);
while (m_receiveDataQueue.size() > 0)
{
data.push_back(m_receiveDataQueue.front());
m_receiveDataQueue.pop_front();
}
}
void DequeReceiveMessage(ReceivedData& msg)
{
CriticalSectionLocker lock(&m_receiveQueLock);
if (m_receiveDataQueue.size() > 0)
{
msg = m_receiveDataQueue.front();
m_receiveDataQueue.pop_front();
}
}
template <class T>
void EnqueReceiveMessage(T&& data)
{
CriticalSectionLocker lock(&m_receiveQueLock);
if (m_receiveDataQueue.size() <= MAX_RECEIVE_QUEUE_SIZE)
{
m_receiveDataQueue.push_back(data);
}
else
{
static int s_nLogCount = 0;
if (s_nLogCount % 100 == 0)
{
DEBUG_LOG2("Max queue size was reached handle id: %d in %s", Handle(), Name().c_str());
}
s_nLogCount++;
}
}
NetworkType GetNetworkType() const
{
return m_netType;
}
private:
ServerData(const ServerData&);
ServerData& operator=(const ServerData&);
private:
bool m_bEnabled; //!< This member flags if this reciever is enabled for receiving incoming connections.
int m_Handle; //!< This member holds the handle for this receiver.
SOCKET m_Socket; //!< This member holds the socket information for this receiver.
unsigned long m_nIPAddress; //!< This member holds an IP address the socket is bound to.
deque < ReceivedData > m_receiveDataQueue;
CRITICAL_SECTION m_receiveQueLock;
CRITICAL_SECTION m_objectLock;
string m_sName;
NetworkType m_netType;
deque<OverlappedEx*> m_olps;
size_t m_ovlpIndex;
};
#endif
your implementation of void Release() have no sense - you decrement m_refCount and so what ? must be
void Release()
{
if (!InterlockedDecrement(&m_refCount)) delete this;
}
as result you never free OverlappedEx* data - this what i just view and this give memory leak.
also can advice - use WaitForSingleObject(CCommunicationManager::s_hShutdownEvent, 0); this is bad idea for detect shutdown. call only GetQueuedCompletionStatus and for shutdown call PostQueuedCompletionStatus(s_IOCompletionPort, 0, 0, 0) several times(number or threads listen on s_IOCompletionPort) and if thread view pOverlapped==0 - just exit.
use
OverlappedEx* data = static_cast<OverlappedEx*>(pOverlapped);
instead of reinterpret_cast
make ~OverlappedEx() private - it must not be direct called, only via Release
olp->Release();
m_olps.push_back(olp);
after you call Release() on object you must not it more access here, so or olp->Release() or m_olps.push_back(olp); but not both. this kill all logic of Release may be you need overwrite operator delete of OverlappedEx and inside it call m_olps.push_back(olp); and of course overwrite operator new too
again (OVERLAPPED*)olp - for what reinterpret_cast here ? because you inherit own struct from OVERLAPPED compiler auto do type cast here
i have 3 thread and 2 shared resources, which need some locking...i tried to illustrate the resources with 2 buffers...
- thread 1 can only access resource 1
- thread 2 can access resource 1 and 2
- thread 3 can access resource 1 and 2
can someone tell me why the following locking fails? since thread2 and thread3 will access resource 1 and 2...i thought i could use try_lock? ...it seems the issue pops up, when thread2 and thread3 is only able to lock 1 mutex at a time...any idea?
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <algorithm>
#include <cassert>
using namespace std;
class SynchronizationTest {
private:
mutex lock_r1;
mutex lock_r2;
vector<pair<string, int>> buffer_r1;
vector<pair<string, int>> buffer_r2;
unsigned int buffer_r1_max_size;
unsigned int buffer_r2_max_size;
bool buffer_r1_inc_element(const string &thread_id) {
if (buffer_r1.size() == buffer_r1_max_size) {
return true;
}
if (buffer_r1.size() == 0) {
buffer_r1.push_back(make_pair(thread_id, 0));
}
else {
int last_val = buffer_r1.back().second;
buffer_r1.push_back(make_pair(thread_id, ++last_val));
}
return false;
}
bool buffer_r2_inc_element(const string &thread_id) {
if (buffer_r2.size() == buffer_r2_max_size) {
return true;
}
if (buffer_r2.size() == 0) {
buffer_r2.push_back(make_pair(thread_id, 0));
}
else {
int last_val = buffer_r2.back().second;
buffer_r2.push_back(make_pair(thread_id, ++last_val));
}
return false;
}
public:
SynchronizationTest(int buff_r1_size, int buff_r2_size) : buffer_r1_max_size(buff_r1_size),
buffer_r2_max_size(buff_r2_size) {}
void thread1() {
bool buffer_r1_full = false;
while (!buffer_r1_full) {
{
unique_lock<mutex> l(lock_r1, std::defer_lock);
if (l.try_lock()) {
buffer_r1_full = buffer_r1_inc_element("thread1");
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
void thread2() {
bool buffer_r1_full = false;
bool buffer_r2_full = false;
while (!buffer_r1_full || !buffer_r2_full) {
{
unique_lock<mutex> lock1(lock_r1, defer_lock);
unique_lock<mutex> lock2(lock_r2, defer_lock);
int result = try_lock(lock1, lock2);
if(result == -1) {
buffer_r1_full = buffer_r1_inc_element("thread2");
buffer_r2_full = buffer_r2_inc_element("thread2");
}
else if(result != 0) {
buffer_r1_full = buffer_r1_inc_element("thread2");
}
else if(result != 1) {
buffer_r2_full = buffer_r2_inc_element("thread2");
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
void thread3() {
bool buffer_r1_full = false;
bool buffer_r2_full = false;
while (!buffer_r1_full || !buffer_r2_full) {
{
unique_lock<mutex> lock1(lock_r1, defer_lock);
unique_lock<mutex> lock2(lock_r2, defer_lock);
int result = try_lock(lock1, lock2);
if(result == -1) {
buffer_r1_full = buffer_r1_inc_element("thread3");
buffer_r2_full = buffer_r2_inc_element("thread3");
}
else if(result != 0) {
buffer_r1_full = buffer_r1_inc_element("thread3");
}
else if(result != 1) {
buffer_r2_full = buffer_r2_inc_element("thread3");
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
void print_buffer() {
for_each(buffer_r1.begin(), buffer_r1.end(), [](pair<string, int> p) { cout << p.first.c_str() << " " << p.second << endl; });
cout << '\n';
for_each(buffer_r2.begin(), buffer_r2.end(), [](pair<string, int> p) { cout << p.first.c_str() << " " << p.second << endl; });
}
};
int main() {
// your code goes here
SynchronizationTest st(20, 20);
thread t1(&SynchronizationTest::thread1, &st);
thread t2(&SynchronizationTest::thread2, &st);
thread t3(&SynchronizationTest::thread3, &st);
t1.join();
t2.join();
t3.join();
st.print_buffer();
return 0;
}
std::try_lock does not work that way. If it returns -1, all locks are held. If it returns a non-negative integer, no locks are held. The returned value tells which lock failed, but any locks that were locked successfully are released before try_lock returns.
problem solved:
unique_lock<mutex> lock1(lock_r1, defer_lock);
unique_lock<mutex> lock2(lock_r2, defer_lock);
bool result1 = lock1.try_lock();
bool result2 = lock2.try_lock();
if(result1 && result2) {
buffer_r1_full = buffer_r1_inc_element("thread2");
buffer_r2_full = buffer_r2_inc_element("thread2");
}
else if(result1) {
buffer_r1_full = buffer_r1_inc_element("thread2");
}
else if(result2) {
buffer_r2_full = buffer_r2_inc_element("thread2");
}
Unfortunately the cygwin GCC 4.5.3 pthread library implementation doesn't support the POSIX standard function
int pthread_mutex_timedlock(pthread_mutex_t* mutex, struct timespec* abstime);
Has anyone a good idea how to implement a good workaround for this method in a mutex wrapper class? May be using pthread_mutex_trylock() with a (milliseconds based) nanosleep() call?
I don't have a good feeling about the latter idea, but anyway the C++ implementation could look like this:
bool MyPosixMutexWrapper::try_lock(const TimeDuration<>& timeout)
{
if(valid)
{
if(timeout == TimeDuration<>::Zero)
{
if(pthread_mutex_trylock(&mutexHandle) == 0)
{
return true;
}
}
else
{
struct timespec now;
clock_gettime(CLOCK_REALTIME,&now);
TimeDuration<> tnow(now);
tnow += timeout;
struct timespec until = tnow.getNativeValue();
#if defined(_POSIX_TIMEOUTS)
if(pthread_mutex_timedlock(&mutexHandle,&until) == 0)
{
return true;
}
#else
long milliseconds = timeout.milliseconds();
while(milliseconds > 0)
{
if(pthread_mutex_trylock(&mutexHandle) == 0)
{
return true;
}
struct timespec interval;
struct timespec remaining;
interval.tv_sec = 0;
interval.tv_nsec = 1000000;
do
{
remaining.tv_sec = 0;
remaining.tv_nsec = 0;
if(nanosleep(&interval,&remaining) < 0)
{
if(errno == EINTR)
{
interval.tv_sec = remaining.tv_sec;
interval.tv_nsec = remaining.tv_nsec;
}
else
{
return false;
}
}
clock_gettime(CLOCK_REALTIME,&now);
tnow = TimeDuration<>(now);
if(tnow >= TimeDuration(until))
{
return pthread_mutex_trylock(&mutexHandle) == 0;
}
} while(remaining.tv_sec > 0 || remaining.tv_nsec > 0);
--milliseconds;
}
#endif
}
}
return pthread_mutex_trylock(&mutexHandle) == 0;
}
Does anyone have a better idea or improvments for this code?
My suggestion would be to use a pthread_cond_timedwait to mimic your timed lock. The trick here is that timed_mutex_ is never held for very long, since waiting on timed_cond_ releases the lock. timed_mutex_ is also released immediately after locked_ is set or unset.
struct MutexGuard {
pthread_mutex_t &mutex_;
MutexGuard (pthread_mutex_t &m) : mutex_(m) {
pthread_mutex_lock(&mutex_);
}
~MutexGuard () {
pthread_mutex_unlock(&mutex_);
}
};
struct TimedMutex {
pthread_mutex_t timed_mutex_;
pthread_cond_t timed_cond_;
bool locked_;
TimedMutex ()
: timed_mutex_(), timed_cond_(), locked_(false) {
pthread_mutex_init(&timed_mutex_, 0);
pthread_cond_init(&timed_cond_, 0);
}
~TimedMutex () {
pthread_cond_destroy(&timed_cond_);
pthread_mutex_destroy(&timed_mutex_);
}
int lock (const struct timespec *t) {
MutexGuard g(timed_mutex_);
while (locked_) {
int r = pthread_cond_timedwait(&timed_cond_, &timed_mutex_, t);
if (r < 0) return r;
}
locked_ = true;
return 0;
}
void lock () {
MutexGuard g(timed_mutex_);
while (locked_) {
pthread_cond_wait(&timed_cond_, &timed_mutex_);
}
locked_ = true;
}
void unlock () {
MutexGuard g(timed_mutex_);
locked_ = false;
pthread_cond_signal(&timed_cond_);
}
};