Crash when disconnecting from SQLite database - c++

I'm trying to write a C++ program that will communicate with different DB providers. Everything works fine now, however upon exiting I'm trying to close the connection and the disconnect command crashes. At the moment I'm testing with SQLite, so it probably belong to this specific one.
Do I have to close the connection to the SQLite upon program termination? I believe generally it is a good idea to release the resources the program is using, but what about this case? I mean in this case the SQLite DB file will be released back to the system when the program exits, so its not actually a loss.
Thank you.
[EDIT]
As requested I'm submitting the code that I use.
In DLL1 (database.h):
#ifndef DBMANAGER_DATABASE
#define DBMANAGER_DATABASE
class __declspec(dllexport) Database
{
public:
Database();
virtual ~Database();
static void *operator new(size_t size);
static void operator delete(void *ptr, size_t size);
};
#endif
In DLL1 (database.cpp)
#include <string>
#include "database.h"
Database::Database()
{
}
Database::~Database()
{
}
void *Database::operator new(std::size_t size)
{
return ::operator new( size );
}
void Database::operator delete(void *ptr, std::size_t size)
{
return ::operator delete( ptr );
}
In DLL2: (database_sqlite.h):
#ifndef DBMANAGER_SQLITE
#define DBMANAGER_SQLITE
class __declspec(dllexport) SQLiteDatabase : public Database
{
public:
SQLiteDatabase();
virtual ~SQLiteDatabase();
virtual int Connect(const char *selectedDSN, std::vector<std::wstring> &errorMsg);
protected:
void GetErrorMessage(int code, std::wstring &errorMsg);
private:
sqlite3 *m_db;
};
#endif
In DLL2: (database_sqlite.cpp)
#ifdef WIN32
#include <windows.h>
#pragma execution_character_set("utf-8")
#endif
#include <vector>
#include <string>
#include <sqlext.h>
#include "sqlite3.h"
#include "database.h"
#include "database_sqlite.h"
SQLiteDatabase::SQLiteDatabase() : Database()
{
}
SQLiteDatabase::~SQLiteDatabase()
{
sqlite3_close( m_db );
}
int SQLiteDatabase::Connect(const char *selectedDSN, std::vector<std::wstring> &errorMsg)
{
int result = 0;
std::wstring errorMessage;
int res = sqlite3_open( selectedDSN, &m_db );
if( res != SQLITE_OK )
{
// get error messages GetErrorMessage( res, errorMessage );
errorMsg.push_back( errorMessage );
result = 1;
}
else
{
res = sqlite3_exec( m_db, "PRAGMA foreign_keys = ON", NULL, NULL, NULL );
if( res != SQLITE_OK )
{
// get error message GetErrorMessage( res, errorMessage );
errorMsg.push_back( errorMessage );
result = 1;
}
}
return result;
}
In DLL3: (dialogs.cpp)
#ifdef __GNUC__
#pragma implementation "dialogs.h"
#endif
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include <vector>
#include "sqlite3ext.h"
#include "database.h"
#include "database_sqlite.h"
#ifdef _WINDOWS
BOOL APIENTRY DllMain( HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
{
lpReserved = lpReserved;
hModule = hModule;
int argc = 0;
char **argv = NULL;
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
#endif
extern "C" __declspec(dllexport) Database *DatabaseProfile(Database *db)
{
db = new SQLiteDatabase;
return db;
}
In main application (test_app.cpp):
#include "stdafx.h"
#include "database.h"
#include <windows.h>
#include <stdio.h>
typedef Database *(__cdecl *MYFUNC)(Database *);
class A
{
public:
A(Database *db)
{
m_db = NULL;
HINSTANCE hInst = LoadLibrary( TEXT( "dialogs.dll" ) );
MYFUNC func = (MYFUNC) GetProcAddress( hInst, "DatabaseProfile" );
m_db = func( db );
}
~A()
{
}
Database *GetDatabase()
{
return m_db;
}
private:
Database *m_db;
};
int _tmain(int argc, _TCHAR* argv[])
{
Database *db = NULL, *m_db;
A *a = new A( db );
m_db = a->GetDatabase();
delete m_db;
delete a;
return 0;
}
[EDIT]
Running this code I am getting the crash executing "delete "m_db" line. SQLite is compiled in from source code.
Any idea?
Thank you.

Related

dflcn c++ script alternative for windows [duplicate]

I wrote a c-code designed for linux platform.
Now, I want to make it cross-platform so to use in Windows as-well.
In my code, I dlopen an so file and utilize the functions inside it.
Below is how my code looks like. But I just found out that in windows, the way to load and use dynamic library is quite different.
void *mydynlib
mydynlib= dlopen("/libpath/dynlib.so",RTLD_LAZY);
void (*dynfunc1)() = dlsym(mydynlib,"dynfunc1");
void (*dynfunc2)(char*, char*, double) = dlsym(mydynlib,"dynfunc2");
int (*dynfunc3)() = dlsym(mydynlib,"dynfunc3");
From what I found, I need to use LoadLibrary & GetProcAddress instead of dlopen & dlsym. However, I do not know how to convert above line for windows using those. I've tried to search some examples for hours but couldn't find exact solution. If someone had this kind of experience, please give me a tip.
Excuse me if this is too obvious problem. I'm quite new to C. I usually write my program in python.
Once in my youth I created something like this:
/* dlfcn.h */
#ifndef DLFCN_H
#define DLFCN_H
#define RTLD_GLOBAL 0x100 /* do not hide entries in this module */
#define RTLD_LOCAL 0x000 /* hide entries in this module */
#define RTLD_LAZY 0x000 /* accept unresolved externs */
#define RTLD_NOW 0x001 /* abort if module has unresolved externs */
/*
How to call in Windows:
void *h = dlopen ("path\\library.dll", flags)
void (*fun)() = dlsym (h, "entry")
*/
#ifdef __cplusplus
extern "C" {
#endif
void *dlopen (const char *filename, int flag);
int dlclose (void *handle);
void *dlsym (void *handle, const char *name);
const char *dlerror (void);
#ifdef __cplusplus
}
#endif
#endif
and dlfcn.c:
/* dlfcn.c */
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
static struct {
long lasterror;
const char *err_rutin;
} var = {
0,
NULL
};
void *dlopen (const char *filename, int flags)
{
HINSTANCE hInst;
hInst= LoadLibrary (filename);
if (hInst==NULL) {
var.lasterror = GetLastError ();
var.err_rutin = "dlopen";
}
return hInst;
}
int dlclose (void *handle)
{
BOOL ok;
int rc= 0;
ok= FreeLibrary ((HINSTANCE)handle);
if (! ok) {
var.lasterror = GetLastError ();
var.err_rutin = "dlclose";
rc= -1;
}
return rc;
}
void *dlsym (void *handle, const char *name)
{
FARPROC fp;
fp= GetProcAddress ((HINSTANCE)handle, name);
if (!fp) {
var.lasterror = GetLastError ();
var.err_rutin = "dlsym";
}
return (void *)(intptr_t)fp;
}
const char *dlerror (void)
{
static char errstr [88];
if (var.lasterror) {
sprintf (errstr, "%s error #%ld", var.err_rutin, var.lasterror);
return errstr;
} else {
return NULL;
}
}
You could use a set of macros that change depending on the OS you're on:
#ifdef __linux__
#define LIBTYPE void*
#define OPENLIB(libname) dlopen((libname), RTLD_LAZY)
#define LIBFUNC(lib, fn) dlsym((lib), (fn))
#elif defined(WINVER)
#define LIBTYPE HINSTANCE
#define OPENLIB(libname) LoadLibraryW(L ## libname)
#define LIBFUNC(lib, fn) GetProcAddress((lib), (fn))
#endif

std containers leaking memory on dll

I load a dll with win32 LoadLibrary, and when I am done with it, I call FreeLibrary, destorying all the memory allocated in the dll ect... Actually, memory leak problem only occures with std containers. It seems they are not willing to release their memory on destroy. Here is the code that leaks.
namespace ToolKit
{
class Game : public GamePlugin
{
public:
void Init(ToolKit::Main* master);
void Destroy();
void Frame(float deltaTime, Viewport* viewport);
void Resize(int width, int height);
void Event(SDL_Event event);
std::vector<int> point; // If I remove this line, no leaks are reported.
};
}
extern "C" TK_GAME_API ToolKit::Game * __stdcall GetInstance()
{
return new ToolKit::Game(); // Instance is deleted in the caller process than FreeLibrary() is called.
}
All functions are no-op in GamePlugin, and the process is not reporting any memory issue if there is no std container. I trap the leak in here. For the completion, I am sharing my standart CRT memory dump code.
int main(int argc, char* argv[])
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
return ToolKit_Main(argc, argv);
}
Load and unload code for the dll
void PluginManager::Load(const String& name)
{
HINSTANCE hinstLib;
TKPROC ProcAdd;
BOOL fRunTimeLinkSuccess = FALSE;
String dllName = name;
hinstLib = LoadLibrary(dllName.c_str());
if (hinstLib != NULL)
{
m_moduleHandle = (void*)hinstLib;
ProcAdd = (TKPROC)GetProcAddress(hinstLib, "GetInstance");
if (NULL != ProcAdd)
{
fRunTimeLinkSuccess = TRUE;
m_plugin = (ProcAdd)();
m_plugin->Init(ToolKit::Main::GetInstance());
}
}
if (!fRunTimeLinkSuccess)
{
m_reporterFn("Can not load plugin module " + dllName);
}
}
void PluginManager::Unload()
{
if (m_plugin)
{
m_plugin->Destroy();
SafeDel(m_plugin);
}
if (m_moduleHandle)
{
FreeLibrary((HINSTANCE)m_moduleHandle);
m_moduleHandle = nullptr;
}
}
Inorder to add some more clarification to the question, I am describing the program flow here:
PluginManager::Load loads the dll
GetInstance function is fetched from the dll
GetInstance return a plugin instance and it is stored in m_plugin
PluginManager::Unload deletes m_plugin and free the dll.
Here is the minimalcase that reproduces the leak.
Process side:
#include <stdio.h>
#include <cstdlib>
#include <crtdbg.h>
#include <string>
#include <functional>
#include <Windows.h>
#include "Plugin.h"
using namespace std;
class PluginManager
{
public:
void Load(const string& plugin);
void Unload();
public:
GamePlugin* m_plugin = nullptr;
void* m_moduleHandle = nullptr;
};
typedef GamePlugin* (__cdecl* TKPROC)();
void PluginManager::Load(const string& name)
{
HINSTANCE hinstLib;
TKPROC ProcAdd;
hinstLib = LoadLibrary(name.c_str());
if (hinstLib != NULL)
{
m_moduleHandle = (void*)hinstLib;
ProcAdd = (TKPROC)GetProcAddress(hinstLib, "GetInstance");
if (NULL != ProcAdd)
{
m_plugin = (ProcAdd)();
m_plugin->Init();
}
}
}
void PluginManager::Unload()
{
if (m_plugin)
{
m_plugin->Destroy();
delete m_plugin;
}
if (m_moduleHandle)
{
FreeLibrary((HINSTANCE)m_moduleHandle);
m_moduleHandle = nullptr;
}
}
int main(int argc, char* argv[])
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
PluginManager* pm = new PluginManager();
pm->Load("plugin.dll");
pm->Unload();
delete pm;
return 0;
}
Plugin interface:
#pragma once
#ifdef _WIN32
# ifdef TK_EXPORTS
# define TK_GAME_API __declspec(dllexport)
# else
# define TK_GAME_API __declspec(dllimport)
# endif
#elif
# define TK_GAME_API
#endif
struct GamePlugin
{
virtual void Init() = 0;
virtual void Destroy() = 0;
virtual void Frame() = 0;
};
DLL side:
#define TK_EXPORTS
#include "Plugin.h"
#include <vector>
class Game : public GamePlugin
{
public:
void Init() {}
void Destroy() {}
void Frame() {}
std::vector<int> point;
};
extern "C" TK_GAME_API GamePlugin * __stdcall GetInstance()
{
return new Game();
}
Exactly the same, if we remove the std::vector<int> point, there is no leak.
As can be seen in the minimal case, I am creating the plugin instance in the dll however deleting it in the process / executable. Eventough the memory is being freed, it gets reported as leak because that memory allocated within the dll and not freed there. Wow what a hassle was that ....
There are better ways of doing this, but in case some one lives the same problem, here is a quick fix.
Process:
void PluginManager::Unload()
{
if (m_plugin)
{
m_plugin->Destroy();
m_plugin = nullptr; // Clear the memory in where it is allocated.
}
if (m_moduleHandle)
{
FreeLibrary((HINSTANCE)m_moduleHandle);
m_moduleHandle = nullptr;
}
}
DLL:
void Destroy() { delete this; } // Now CRT Debug is happy. No false leak repots.

Google breakpad ThreadEntry function crash on MIPS architecture

I had download Google breakpad source to do some testing, the demo can work normal on X64 and ARM64, but on MIPS64 it does not generate minidump file and child thread will crash after sys_clone under ExceptionHandler::GenerateDump();
I checked the input address of the child thread, found the address is reduced by 16 bytes, my kernel revision is :
[root#neo7 breakpad-master]# uname -r
3.10.0-514.26.2.ns7.030.mips64el
My test code is :
#include "../src/client/linux/handler/exception_handler.h"
#include <pthread.h>
#include <iostream>
using namespace std;
static bool dumpCallback(const google_breakpad::MinidumpDescriptor &descriptor,
void *context,
bool succeeded)
{
printf("Dump path: %s\n", descriptor.path());
char cmd[512] = {0};
snprintf(cmd, sizeof(cmd), "echo %s > dump_name", descriptor.path());
system(cmd);
return succeeded;
}
void *TestThread(void* arg)
{
int input = *(int*)arg;
int *a = (int *)(NULL);
*a = 1;
}
int main(int argc, char *argv[])
{
google_breakpad::MinidumpDescriptor descriptor("/tmp");
google_breakpad::ExceptionHandler eh(descriptor,
NULL,
dumpCallback,
NULL,
true,
-1);
//crashHare();
pthread_t threadId;
int input = 12;
int ret = pthread_create(&threadId, NULL, TestThread, (void*)&input);
if(ret != 0)
{
cout<< "create thread error"<<endl;
}
cout<<"main thread running"<<endl;
pthread_join(threadId,NULL);
return 0;
}
I add some printf in ./src/client/linux/handler/exception_handler.cc, before sys_clone and after ThreadEntry, the log is :
struct ThreadArgument {
pid_t pid; // the crashing process
const MinidumpDescriptor* minidump_descriptor;
ExceptionHandler* handler;
const void* context; // a CrashContext structure
size_t context_size;
};
ThreadArgument thread_arg;
thread_arg.handler = this;
thread_arg.minidump_descriptor = &minidump_descriptor_;
thread_arg.pid = getpid();
thread_arg.context = context;
thread_arg.context_size = sizeof(*context);
zzzzzzz &thread_arg:f10ee460 (before sys_clone)
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FS | CLONE_UNTRACED, &thread_arg, NULL, NULL,
NULL);
zzzzzzz child 23889
int ExceptionHandler::ThreadEntry(void *arg) {
zzzzzzz ThreadEntry
zzzzzzz arg:f10ee450 (child thread)
if the type of thread_arg is a int *, there is no address offset problem. If add prefix static for thread_arg, there is no address offset problem too.
static ThreadArgument thread_arg; /* The same goes for malloc, but malloc is not safe */
zzzzzzz &thread_arg:20030060 (before sys_clone)
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FS | CLONE_UNTRACED, &thread_arg, NULL, NULL,
NULL);
zzzzzzz child 22399
int ExceptionHandler::ThreadEntry(void *arg) {
zzzzzzz ThreadEntry
zzzzzzz arg:20030060 (child thread)
And I write an another code to test sys_clone under signal processing function:
#include <errno.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/signal.h>
#include <sys/ucontext.h>
#include <sys/user.h>
#include <ucontext.h>
#include <algorithm>
#include <utility>
#include <vector>
#include "src/third_party/lss/linux_syscall_support.h"
#include "src/common/memory_allocator.h"
using namespace google_breakpad;
unsigned char *stack = NULL;
void my_memset(void* ip, char c, size_t len) {
char* p = (char *) ip;
while (len--)
*p++ = c;
}
struct ThreadArgument {
pid_t pid; // the crashing process
const void* minidump_descriptor;
void* handler;
const void* context; // a CrashContext structure
size_t context_size;
};
int ThreadEntry(void *arg) {
printf("arg:%x\n", arg);
const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg);
printf("thread_arg:%x\n", thread_arg);
return 0;
}
void GenerateDump(int signo) {
static const unsigned kChildStackSize = 16000;
PageAllocator allocator;
uint8_t* stack = reinterpret_cast<uint8_t*>(allocator.Alloc(kChildStackSize));
if (!stack)
return ;
stack += kChildStackSize;
my_memset(stack - 16, 0, 16);
ThreadArgument thread_arg;
thread_arg.handler = (void *) NULL;
thread_arg.minidump_descriptor = (void *) NULL;
thread_arg.pid = getpid();
thread_arg.context = (void *) NULL;
thread_arg.context_size = sizeof(void *);
printf("thread_arg:%x\n", &thread_arg);
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FS | CLONE_UNTRACED, &thread_arg, NULL, NULL,
NULL);
printf("child:%d\n", child);
sleep(1);
return ;
}
int main(void)
{
signal(SIGSEGV, GenerateDump);
int *a = (int *)NULL;
*a = 1;
return 0;
}
It works normal:
thread_arg:ffcb9030
child:8447
arg:ffcb9030
thread_arg:ffcb9030
I wonder why passing the contents of the stack as parameters causes this
address mismatch problem in breakpad.

why this is not a right Producer consumer model and what causes the error when I use stl queue?

there will be a error after the application run a period of time at the line delete busMsg .I don't understand how the error came about.
#include "stdafx.h"
#include "queue.h"
#include <queue>
#include <iostream>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CWinApp theApp;
using namespace std;
CRITICAL_SECTION m_csReceivedMsgQueue;
HANDLE m_hReceivedDataEvent;
HANDLE m_hEventStop;
queue<CBusMsg* > m_qReceivedMsgQueue;
class CBusMsg
{
public:
CBusMsg(WORD nAgentID, WORD nAgentExclue, BYTE* pBuf,int nLen)
{
m_nAgentID=nAgentID;
m_nAgentExclue=nAgentExclue;
m_nLen=nLen;
m_pBuf=new BYTE[m_nLen];
memcpy(m_pBuf,pBuf,nLen);
}
~CBusMsg()
{
if (m_pBuf!=NULL)
delete[] m_pBuf;
}
WORD m_nAgentID; //0:群发,其它:单播
WORD m_nAgentExclue;
BYTE* m_pBuf;
int m_nLen;
};
UINT SendhreadProc( LPVOID pParam)
{
HANDLE hWaitObjList[2]={m_hEventStop,m_hReceivedDataEvent};
bool haveData = false;
DWORD dwWaitRes;
for(;;)
{
if(haveData)//如果还有未处理的数据不等待内核对象直接返回
{
dwWaitRes=::WaitForMultipleObjects(2,hWaitObjList,FALSE,0);
}
else//如果没有未处理的数据不等待内核对象直接返回
{
dwWaitRes=::WaitForMultipleObjects(2,hWaitObjList,FALSE,200);
}
if((dwWaitRes-WAIT_OBJECT_0)==0)//,索引为0的内核对象被触发,也就是停止线程被触发
{
break;
}
haveData = false;
try
{
EnterCriticalSection(&m_csReceivedMsgQueue);
if(m_qReceivedMsgQueue.empty())
{
LeaveCriticalSection(&m_csReceivedMsgQueue);
continue;
}
CBusMsg*& busMsg = m_qReceivedMsgQueue.front();//取队首元素
m_qReceivedMsgQueue.pop();//弹出队首元素
if(NULL==busMsg)
{
LeaveCriticalSection(&m_csReceivedMsgQueue);
continue;
}
//ASSERT(busMsg->m_nLen<=0);
//pAgent->SetData(busMsg->m_pBuf,busMsg->m_nLen);
haveData = !m_qReceivedMsgQueue.empty();
LeaveCriticalSection(&m_csReceivedMsgQueue);
//**************There is the error********************/
delete busMsg;
//********************************************************/
//busMsg = NULL;
//ProcessData(pAgent);
}
catch(...)
{
LeaveCriticalSection(&m_csReceivedMsgQueue);
}
}
//delete pAgent;
return 0;
}
UINT PushData( LPVOID pParam)
{
BYTE pPacket[1000];
memset(pPacket,0,1000);
for (int i=0;i<100000;i++)
{
CBusMsg *pBusMsg;
pPacket[0]= i;
pBusMsg=new CBusMsg(i,0,pPacket,1000);
TRACE("请求向队列加消息\n");
EnterCriticalSection(&m_csReceivedMsgQueue);
TRACE("开始向队列加消息\n");
m_qReceivedMsgQueue.push(pBusMsg);
LeaveCriticalSection(&m_csReceivedMsgQueue);
SetEvent(m_hReceivedDataEvent);
}
return 0;
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
InitializeCriticalSection(&m_csReceivedMsgQueue);
HMODULE hModule = ::GetModuleHandle(NULL);
m_hReceivedDataEvent =::CreateEvent(NULL,FALSE,FALSE,NULL);
m_hEventStop=::CreateEvent(NULL,FALSE,FALSE,NULL);
//创建发送线程
CWinThread* m_pSendThread=AfxBeginThread(SendhreadProc,NULL,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL);
m_pSendThread->m_bAutoDelete=FALSE;
m_pSendThread->ResumeThread();
CWinThread* processThread=AfxBeginThread(PushData,NULL,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL);
processThread->m_bAutoDelete=FALSE;
processThread->ResumeThread();
char str[1000];
cin.getline(str,900);
return nRetCode;
}
The problem might be here
CBusMsg*& busMsg = m_qReceivedMsgQueue.front();//取队首元素
m_qReceivedMsgQueue.pop();//弹出队首元素
You take a reference to the pointer from the queue.
Then you pop the queue making the reference invalid.
Which will make the program crash some times.
This might make you happier
CBusMsg* busMsg = m_qReceivedMsgQueue.front();//取队首元素
m_qReceivedMsgQueue.pop();//弹出队首元素
Why does it crash, because the address that is referenced might be reused for something different before you get to
delete busMsg;
You release the lock just before the delete and in that time another can put something new in the queue using the same address for example if the queue is empty after the .pop. Then the delete doesn't delete the original referenced message but the new one it is referenced to.

Is there a windows concurrency_queue.h equivalent on linux?

Well I am tryng to have a queue which is concurrent, but concurrency_queue isn't standard C++ and it's for windows, linux doesn't have it. Is there anything for linux like this (with the same functions like in the windows equivalent?)?
Edit:
This is needed to port this windows code to linux:
#include <concurrent_queue.h>
#ifdef defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
#define SLEEP(x) { Sleep(x); }
#include <windows.h>
#include <process.h>
#define OS_WINDOWS
#define EXIT_THREAD() { _endthread(); }
#define START_THREAD(a, b) { _beginthread( a, 0, (void *)( b ) ); }
#else
#include <pthread.h>
#define sscanf_s sscanf
#define sprintf_s sprintf
#define EXIT_THREAD() { pthread_exit( NULL ); }
#define START_THREAD(a, b) { pthread_t thread;\
pthread_create( &thread, NULL, a, (void *)( b ) ); }
#endif
using namespace std;
using namespace Concurrency;
struct QuedData
{
int start;
int end;
int extraid;
AMX * script;
QuedData(){start = 0;end = 0;extraid = 0;script = NULL;}
QuedData(int start_,int end_,int extraid_, AMX * script_){start = start_;end = end_;extraid = extraid_;script = script_;}
};
struct PassData //thanks to DeadMG for improvements.
{
std::vector<cell> Paths;
int extraid;
AMX * script;
cell MoveCost;
PassData(){extraid = 0;script = NULL;MoveCost = 0;Paths.clear();}
template<typename Iterator> PassData(Iterator begin, Iterator end, int extraid_, cell MoveCost_, AMX * script_)
: Paths(begin, end)
{extraid = extraid_;MoveCost = MoveCost_;script = script_;}
~PassData(){Paths.clear();}
};
concurrent_queue <QuedData> QueueVector;
concurrent_queue <PassData> PassVector;
PassData LocalPass;
void PLUGIN_CALL
ProcessTick()
{
if(PassVector.try_pop(LocalPass))
{
amx_Push(LocalPass.script, LocalPass.MoveCost);
//blabla
}
}
static cell AMX_NATIVE_CALL n_CalculatePath( AMX* amx, cell* params )
{
QueueVector.push(QuedData(params[1],params[2],params[3],amx));
return 1;
}
bool PLUGIN_CALL Load( void **ppData )
{
START_THREAD( Thread::BackgroundCalculator, 0);
return true;
}
QuedData RecievedData;
vector <cell>tbcway;
cell tbccostx;
#ifdef OS_WINDOWS
void Thread::BackgroundCalculator( void *unused )
#else
void *Thread::BackgroundCalculator( void *unused )
#endif
{
while( true ){
if(QueueVector.try_pop(RecievedData)){
dgraph->findPath_r(xNode[RecievedData.start].NodeID ,xNode[RecievedData.end].NodeID,tbcway,tbccostx);
PassVector.push(PassData(tbcway.begin(),tbcway.end(),RecievedData.extraid,tbccostx,RecievedData.script));
}
SLEEP(5);
}
EXIT_THREAD();
}
The Visual C++ concurrent_queue is actually based on the Intel Threading Building Block Library
(If you open concurrent_queue.h header file in VC++ you will see an acknowledgement)
You can get the library from
http://threadingbuildingblocks.org/
The library will run on Linux as well.
I think threadpool does this or an unofficial Boost enhancement called lockfree and should by now be part of Boost::Atomics. I haven't use both but let us know if you have any luck.
I would suggest looking at https://github.com/romanek-adam/boost_locking_queue for the code and the article that goes with it at Implementing a Thread-Safe Queue using Condition Variables