cygwin pthread_mutex_timedlock surrogate - c++

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_);
}
};

Related

Interactive Brokers C++ Error: error: 'min' was not declared in this scope

I am trying to setup the Interactive Brokers API on Ubuntu (18.04). I have installed both the IB Gateway, which is used for communicating with exchanges, as well as other API software for developing trading algorithms in Java, C++, C# and Python. (Which you can find here). The API is written in both Java and C++, and as stated prior it offers support for both. However when attempting to compile an example from their source code there is an error in the EReader.cpp file. I have dealt with several other C++ errors in their code however this one I cannot figure out. Here is the code:
#include "StdAfx.h"
#include "shared_ptr.h"
#include "Contract.h"
#include "EDecoder.h"
#include "EMutex.h"
#include "EReader.h"
#include "EClientSocket.h"
#include "EPosixClientSocketPlatform.h"
#include "EReaderSignal.h"
#include "EMessage.h"
#include "DefaultEWrapper.h"
#define IN_BUF_SIZE_DEFAULT 8192
static DefaultEWrapper defaultWrapper;
EReader::EReader(EClientSocket *clientSocket, EReaderSignal *signal)
: processMsgsDecoder_(clientSocket->EClient::serverVersion(), clientSocket->getWrapper(), clientSocket) {
m_isAlive = true;
m_pClientSocket = clientSocket;
m_pEReaderSignal = signal;
m_needsWriteSelect = false;
m_nMaxBufSize = IN_BUF_SIZE_DEFAULT;
m_buf.reserve(IN_BUF_SIZE_DEFAULT);
}
EReader::~EReader(void) {
m_isAlive = false;
#if defined(IB_WIN32)
WaitForSingleObject(m_hReadThread, INFINITE);
#endif
}
void EReader::checkClient() {
m_needsWriteSelect = !m_pClientSocket->getTransport()-
isOutBufferEmpty();
}
void EReader::start() {
#if defined(IB_POSIX)
pthread_t thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create( &thread, &attr, readToQueueThread, this );
pthread_attr_destroy(&attr);
#elif defined(IB_WIN32)
m_hReadThread = CreateThread(0, 0, readToQueueThread, this, 0, 0);
#else
# error "Not implemented on this platform"
#endif
}
#if defined(IB_POSIX)
void * EReader::readToQueueThread(void * lpParam)
#elif defined(IB_WIN32)
DWORD WINAPI EReader::readToQueueThread(LPVOID lpParam)
#else
# error "Not implemented on this platform"
#endif
{
EReader *pThis = reinterpret_cast<EReader *>(lpParam);
pThis->readToQueue();
return 0;
}
void EReader::readToQueue() {
EMessage *msg = 0;
while (m_isAlive) {
if (m_buf.size() == 0 && !processNonBlockingSelect() && m_pClientSocket->isSocketOK())
continue;
if (!putMessageToQueue())
break;
}
m_pClientSocket->handleSocketError();
m_pEReaderSignal->issueSignal(); //letting client know that socket was closed
}
bool EReader::putMessageToQueue() {
EMessage *msg = 0;
if (m_pClientSocket->isSocketOK())
msg = readSingleMsg();
if (msg == 0)
return false;
m_csMsgQueue.Enter();
m_msgQueue.push_back(ibapi::shared_ptr<EMessage>(msg));
m_csMsgQueue.Leave();
m_pEReaderSignal->issueSignal();
return true;
}
bool EReader::processNonBlockingSelect() {
fd_set readSet, writeSet, errorSet;
struct timeval tval;
tval.tv_usec = 100 * 1000; //100 ms
tval.tv_sec = 0;
if( m_pClientSocket->fd() >= 0 ) {
FD_ZERO( &readSet);
errorSet = writeSet = readSet;
FD_SET( m_pClientSocket->fd(), &readSet);
if (m_needsWriteSelect)
FD_SET( m_pClientSocket->fd(), &writeSet);
FD_SET( m_pClientSocket->fd(), &errorSet);
int ret = select( m_pClientSocket->fd() + 1, &readSet, &writeSet, &errorSet, &tval);
if( ret == 0) { // timeout
return false;
}
if( ret < 0) { // error
m_pClientSocket->eDisconnect();
return false;
}
if( m_pClientSocket->fd() < 0)
return false;
if( FD_ISSET( m_pClientSocket->fd(), &errorSet)) {
// error on socket
m_pClientSocket->onError();
}
if( m_pClientSocket->fd() < 0)
return false;
if( FD_ISSET( m_pClientSocket->fd(), &writeSet)) {
// socket is ready for writing
onSend();
}
if( m_pClientSocket->fd() < 0)
return false;
if( FD_ISSET( m_pClientSocket->fd(), &readSet)) {
// socket is ready for reading
onReceive();
}
return true;
}
return false;
}
void EReader::onSend() {
m_pEReaderSignal->issueSignal();
}
void EReader::onReceive() {
int nOffset = m_buf.size();
m_buf.resize(m_nMaxBufSize);
int nRes = m_pClientSocket->receive(m_buf.data() + nOffset, m_buf.size() - nOffset);
if (nRes <= 0)
return;
m_buf.resize(nRes + nOffset);
}
bool EReader::bufferedRead(char *buf, int size) {
while (size > 0) {
while (m_buf.size() < size && m_buf.size() < m_nMaxBufSize)
if (!processNonBlockingSelect() && !m_pClientSocket->isSocketOK())
return false;
int nBytes = (std::min<unsigned int>)(m_nMaxBufSize, size);
std::copy(m_buf.begin(), m_buf.begin() + nBytes, buf);
std::copy(m_buf.begin() + nBytes, m_buf.end(), m_buf.begin());
m_buf.resize(m_buf.size() - nBytes);
size -= nBytes;
buf += nBytes;
}
return true;
}
EMessage * EReader::readSingleMsg() {
if (m_pClientSocket->usingV100Plus()) {
int msgSize;
if (!bufferedRead((char *)&msgSize, sizeof(msgSize)))
return 0;
msgSize = htonl(msgSize);
if (msgSize <= 0 || msgSize > MAX_MSG_LEN)
return 0;
std::vector<char> buf = std::vector<char>(msgSize);
if (!bufferedRead(buf.data(), buf.size()))
return 0;
return new EMessage(buf);
}
else {
const char *pBegin = 0;
const char *pEnd = 0;
int msgSize = 0;
while (msgSize == 0)
{
if (m_buf.size() >= m_nMaxBufSize * 3/4)
m_nMaxBufSize *= 2;
if (!processNonBlockingSelect() && !m_pClientSocket->isSocketOK())
return 0;
pBegin = m_buf.data();
pEnd = pBegin + m_buf.size();
msgSize = EDecoder(m_pClientSocket->EClient::serverVersion(), &defaultWrapper).parseAndProcessMsg(pBegin, pEnd);
}
std::vector<char> msgData(msgSize);
if (!bufferedRead(msgData.data(), msgSize))
return 0;
if (m_buf.size() < IN_BUF_SIZE_DEFAULT && m_buf.capacity() > IN_BUF_SIZE_DEFAULT)
{
m_buf.resize(m_nMaxBufSize = IN_BUF_SIZE_DEFAULT);
m_buf.shrink_to_fit();
}
EMessage * msg = new EMessage(msgData);
return msg;
}
}
ibapi::shared_ptr<EMessage> EReader::getMsg(void) {
m_csMsgQueue.Enter();
if (m_msgQueue.size() == 0) {
m_csMsgQueue.Leave();
return ibapi::shared_ptr<EMessage>();
}
ibapi::shared_ptr<EMessage> msg = m_msgQueue.front();
m_msgQueue.pop_front();
m_csMsgQueue.Leave();
return msg;
}
void EReader::processMsgs(void) {
m_pClientSocket->onSend();
checkClient();
ibapi::shared_ptr<EMessage> msg = getMsg();
if (!msg.get())
return;
const char *pBegin = msg->begin();
while (processMsgsDecoder_.parseAndProcessMsg(pBegin, msg->end()) > 0)
{
msg = getMsg();
if (!msg.get())
break;
pBegin = msg->begin();
}
}
The error I get it is the following:
error: 'min' was not declared in this scope int nBytes =
min(m_nMaxBuffSize, size);
I have had to do other things such as editing other source code and makefiles, I am stuck here. Any insight would be appreciated.
In my version 973 source at that line I have
int nBytes = (std::min<unsigned int>)(m_nMaxBufSize, size);
Make sure you are using the latest version. The problem may be an example of what happens here Why is "using namespace std" considered bad practice?

How to achieve event compression in C++

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.

C++ [Microsoft][ODBC SQL Server Driver]String data, right truncation

I need help with ODBC prepared queries. I working on Windows 10(x64). My VPS server is Windows Server 2012(x64). My compiled aplication is 32 bit. I need prepared queries to make SQL Injection not possible. But have one big problem.
Error:
[QueryManager] State (22001), Diagnostic: [Microsoft][ODBC SQL Server Driver]String data, right truncation
Code:
gQueryManager.BindParameterAsString(1,Name,sizeof(Name));
gQueryManager.ExecQuery("SELECT Value FROM Table WHERE Name=?");
gQueryManager.Fetch();
...
gQueryManager.Close();
This is source code of Query Manager I using:
// QueryManager.cpp: implementation of the CQueryManager class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "QueryManager.h"
#include "Util.h"
CQueryManager gQueryManager;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CQueryManager::CQueryManager() // OK
{
this->m_SQLEnvironment = SQL_NULL_HANDLE;
this->m_SQLConnection = SQL_NULL_HANDLE;
this->m_STMT = SQL_NULL_HANDLE;
this->m_RowCount = -1;
this->m_ColCount = -1;
memset(this->m_SQLColName,0,sizeof(this->m_SQLColName));
memset(this->m_SQLData,0,sizeof(this->m_SQLData));
SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&this->m_SQLEnvironment);
SQLSetEnvAttr(this->m_SQLEnvironment,SQL_ATTR_ODBC_VERSION,(SQLPOINTER)SQL_OV_ODBC3,SQL_IS_INTEGER);
}
CQueryManager::~CQueryManager() // OK
{
this->Disconnect();
}
bool CQueryManager::Connect(char* odbc,char* user,char* pass) // OK
{
strcpy_s(this->m_odbc,odbc);
strcpy_s(this->m_user,user);
strcpy_s(this->m_pass,pass);
if(SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_DBC,this->m_SQLEnvironment,&this->m_SQLConnection)) == 0)
{
return 0;
}
if(SQL_SUCCEEDED(SQLConnect(this->m_SQLConnection,(SQLCHAR*)this->m_odbc,SQL_NTS,(SQLCHAR*)this->m_user,SQL_NTS,(SQLCHAR*)this->m_pass,SQL_NTS)) == 0)
{
return 0;
}
if(SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_STMT,this->m_SQLConnection,&this->m_STMT)) == 0)
{
return 0;
}
else
{
return 1;
}
}
void CQueryManager::Disconnect() // OK
{
if(this->m_STMT != SQL_NULL_HANDLE)
{
SQLFreeHandle(SQL_HANDLE_STMT,this->m_STMT);
this->m_STMT = SQL_NULL_HANDLE;
}
if(this->m_SQLConnection != SQL_NULL_HANDLE)
{
SQLFreeHandle(SQL_HANDLE_DBC,this->m_SQLConnection);
this->m_SQLConnection = SQL_NULL_HANDLE;
}
if(this->m_SQLEnvironment != SQL_NULL_HANDLE)
{
SQLFreeHandle(SQL_HANDLE_ENV,this->m_SQLEnvironment);
this->m_SQLEnvironment = SQL_NULL_HANDLE;
}
}
void CQueryManager::Diagnostic(char* query) // OK
{
LogAdd(LOG_BLACK,"%s",query);
SQLINTEGER NativeError;
SQLSMALLINT RecNumber=1,BufferLength;
SQLCHAR SqlState[6],MessageText[SQL_MAX_MESSAGE_LENGTH];
while(SQLGetDiagRec(SQL_HANDLE_STMT,this->m_STMT,(RecNumber++),SqlState,&NativeError,MessageText,sizeof(MessageText),&BufferLength) != SQL_NO_DATA)
{
LogAdd(LOG_RED,"[QueryManager] State (%s), Diagnostic: %s",SqlState,MessageText);
}
if(strcmp((char*)SqlState,"08S01") == 0)
{
this->Connect(this->m_odbc,this->m_user,this->m_pass);
}
}
bool CQueryManager::ExecQuery(char* query,...) // OK
{
char buff[4096];
va_list arg;
va_start(arg,query);
vsprintf_s(buff,query,arg);
va_end(arg);
SQLRETURN result;
if(SQL_SUCCEEDED((result=SQLExecDirect(this->m_STMT,(SQLCHAR*)buff,SQL_NTS))) == 0 && result != SQL_NO_DATA)
{
this->Diagnostic(buff);
return 0;
}
SQLRowCount(this->m_STMT,&this->m_RowCount);
if(this->m_RowCount == 0){return 1;}
SQLNumResultCols(this->m_STMT,&this->m_ColCount);
if(this->m_ColCount == 0){return 1;}
if(this->m_ColCount > MAX_COLUMNS){return 0;}
memset(this->m_SQLColName,0,sizeof(this->m_SQLColName));
memset(this->m_SQLData,0,sizeof(this->m_SQLData));
for(int n=0;n < this->m_ColCount;n++)
{
SQLDescribeCol(this->m_STMT,(n+1),this->m_SQLColName[n],sizeof(this->m_SQLColName[n]),0,0,0,0,0);
SQLBindCol(this->m_STMT,(n+1),SQL_C_CHAR,this->m_SQLData[n],sizeof(this->m_SQLData[n]),&this->m_SQLDataLen[n]);
}
return 1;
}
void CQueryManager::Close() // OK
{
SQLCloseCursor(this->m_STMT);
SQLFreeStmt(this->m_STMT,SQL_UNBIND);
}
SQLRETURN CQueryManager::Fetch() // OK
{
return SQLFetch(this->m_STMT);
}
int CQueryManager::FindIndex(char* ColName) // OK
{
for(int n=0;n < this->m_ColCount;n++)
{
if(_stricmp(ColName,(char*)this->m_SQLColName[n]) == 0)
{
return n;
}
}
return -1;
}
int CQueryManager::GetResult(int index) // OK
{
return atoi(this->m_SQLData[index]);
}
int CQueryManager::GetAsInteger(char* ColName) // OK
{
int index = this->FindIndex(ColName);
if(index == -1)
{
return index;
}
else
{
return atoi(this->m_SQLData[index]);
}
}
float CQueryManager::GetAsFloat(char* ColName) // OK
{
int index = this->FindIndex(ColName);
if(index == -1)
{
return (float)index;
}
else
{
return (float)atof(this->m_SQLData[index]);
}
}
__int64 CQueryManager::GetAsInteger64(char* ColName) // OK
{
int index = this->FindIndex(ColName);
if(index == -1)
{
return index;
}
else
{
return _atoi64(this->m_SQLData[index]);
}
}
void CQueryManager::GetAsString(char* ColName,char* OutBuffer,int OutBufferSize) // OK
{
int index = this->FindIndex(ColName);
if(index == -1)
{
memset(OutBuffer,0,OutBufferSize);
}
else
{
strncpy_s(OutBuffer,OutBufferSize,this->m_SQLData[index],(OutBufferSize-1));
}
}
void CQueryManager::GetAsBinary(char* ColName,BYTE* OutBuffer,int OutBufferSize) // OK
{
int index = this->FindIndex(ColName);
if(index == -1)
{
memset(OutBuffer,0,OutBufferSize);
}
else
{
this->ConvertStringToBinary(this->m_SQLData[index],sizeof(this->m_SQLData[index]),OutBuffer,OutBufferSize);
}
}
void CQueryManager::BindParameterAsString(int ParamNumber,void* InBuffer,int ColumnSize) // OK
{
this->m_SQLBindValue[(ParamNumber-1)] = SQL_NTS;
SQLBindParameter(this->m_STMT,ParamNumber,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_VARCHAR,ColumnSize,0,InBuffer,0,&this->m_SQLBindValue[(ParamNumber-1)]);
}
void CQueryManager::BindParameterAsBinary(int ParamNumber,void* InBuffer,int ColumnSize) // OK
{
this->m_SQLBindValue[(ParamNumber-1)] = ColumnSize;
SQLBindParameter(this->m_STMT,ParamNumber,SQL_PARAM_INPUT,SQL_C_BINARY,SQL_VARBINARY,ColumnSize,0,InBuffer,0,&this->m_SQLBindValue[(ParamNumber-1)]);
}
void CQueryManager::ConvertStringToBinary(char* InBuff,int InSize,BYTE* OutBuff,int OutSize) // OK
{
int size = 0;
memset(OutBuff,0,OutSize);
for(int n=0;n < InSize,size < OutSize;n++)
{
if(InBuff[n] == 0)
{
break;
}
if((n%2) == 0)
{
OutBuff[size] = ((InBuff[n]>='A')?((InBuff[n]-'A')+10):(InBuff[n]-'0'))*16;
size = size+0;
}
else
{
OutBuff[size] = OutBuff[size] | ((InBuff[n]>='A')?((InBuff[n]-'A')+10):(InBuff[n]-'0'));
size = size+1;
}
}
}
void CQueryManager::ConvertBinaryToString(BYTE* InBuff,int InSize,char* OutBuff,int OutSize) // OK
{
int size = 0;
memset(OutBuff,0,OutSize);
for(int n=0;n < OutSize,size < InSize;n++)
{
if((n%2) == 0)
{
OutBuff[n] = (((InBuff[size]/16)>=10)?('A'+((InBuff[size]/16)-10)):('0'+(InBuff[size]/16)));
size = size+0;
}
else
{
OutBuff[n] = (((InBuff[size]%16)>=10)?('A'+((InBuff[size]%16)-10)):('0'+(InBuff[size]%16)));
size = size+1;
}
}
}

synchronization issue with 3 threads and 2 shared resources in c++11

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");
}

the magic cout that keep my program alive

I wrote a code to implement spin lock and mutex lock.
There is an interesting but. A magic cout can keep my program alive. If I remove the cout, my program will be sleeping forever. (This only happens in Linux. Windows is doing fine)
Any one have a clue?
#include <pthread.h>
#include <iostream>
#include <queue>
#include <sys/time.h>
#include <stdexcept>
#include <cstdio>
#include <cstdlib>
using namespace std;
#define Tcount 10
#define TheLock MutexLock
static inline int TAS(volatile int * ptr) {
unsigned long result;
asm volatile("lock;"
"xchgl %0, %1;"
: "=r"(result), "=m"(*ptr)
: "0"(1), "m"(*ptr)
: "memory");
return result;
}
class SpinLock {
private:
int lock;
pthread_t owner;
public:
SpinLock() {
lock = 0;
}
void getLock() {
while (TAS(&lock) == 1) {
}
owner = pthread_self();
}
void releaseLock() {
if (lock == 0) {
cout << "Spin no lock" << endl;
return;
} else if (owner == pthread_self()) {
owner = NULL;
lock = 0;
} else {
throw runtime_error("Spin can't release");
}
}
};
class MutexLock {
private:
int lock;
pthread_t owner;
queue<pthread_t> q;
SpinLock qLock;
public:
MutexLock() {
lock = 0;
}
void getLock(int id) {
pthread_t self = pthread_self();
cout<<"a"<<endl;// magic cout
if (TAS(&lock) == 0) {
owner = self;
return;
}
qLock.getLock();
q.push(self);
qLock.releaseLock();
while (owner != self) {
}
}
void releaseLock(int id) {
if (lock == 0) {
cout << "Mutex no lock" << endl;
return;
} else if (owner == pthread_self()) {
qLock.getLock();
if (q.empty()) {
owner = NULL;
lock = 0;
} else {
owner = q.front();
q.pop();
}
qLock.releaseLock();
} else {
throw runtime_error("Mutex can't release");
}
}
};
TheLock lock;
int g = 0;
void* run(void* pt) {
int id = (int) pt;
for (int i = 0; i < 10000; i++) {
lock.getLock(id);
//cout<<"Thread "<<id<<" get lock, g="<<g<<endl;
int next = g + 1;
g = next;
//cout<<"Thread "<<id<<" release lock, g="<<g<<endl;
lock.releaseLock(id);
}
return NULL;
}
int main() {
pthread_t th[Tcount];
long mtime, seconds, useconds;
struct timeval start, end;
gettimeofday(&start, NULL);
for (int i = 0; i < Tcount; i++) {
pthread_create(&th[i], NULL, run, (void*) (i+10));
}
for (int i = 0; i < Tcount; i++) {
pthread_join(th[i], 0);
}
gettimeofday(&end, NULL);
seconds = end.tv_sec - start.tv_sec;
useconds = end.tv_usec - start.tv_usec;
mtime = ((seconds) * 1000000 + useconds);
cout << "g=" << g << endl;
cout << "time=" << mtime << endl;
return 0;
}
You cannot implement a mutex by using the volatile keyword as the operations may not be atomic. This means that the OS might switch to a different thread before the operation has completed.
For mutex you have to use the OS. It is the only thing that knows when threads are being switched.