I wrote a simple test application to prove that the threads work:
// Test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
class clsTest {
private:
uintptr_t muintHandle;
static unsigned int __stdcall fnThread(void* pData) {
while( 1 ) {
_sleep(1000);
printf("In fnThread, handle = %d\n", *(uintptr_t*)pData);
}
return 0;
}
public:
clsTest() {
muintHandle = _beginthreadex(0, 0, &clsTest::fnThread, (void*)&muintHandle, 0, 0);
printf("clsTest(), after beginthreadex, handle = %u\n", muintHandle);
}
};
int _tmain(int argc, _TCHAR* argv[]) {
clsTest* pT = NULL;
while(1) {
printf("From _tmain\n");
if ( pT == NULL ) {
pT = new clsTest();
}
_sleep(1000);
}
return 0;
}
The output from this application is:
From _tmain
clsTest(), after beginthreadex, handle = 112
In fnThread, handle = 112
From _tmain
In fnThread, handle = 112
From _tmain
In fnThread, handle = 112
From _tmain
In fnThread, handle = 112
From _tmain
In fnThread, handle = 112
From _tmain
In fnThread, handle = 112
...
Continuously which is exactly what I would expect to see...Now in a much larger project I have a base class:
typedef enum {
eIdle = 0, //Thread is not working at all
eStarted, //Thread has been started but is not fully operational yet
eRunning, //Thread is working normally
ePausing, //Thread is requested to enter the paused state
ePaused, //Thread is paused
eTerminating //Termination has been requested but not completed yet
} eThreadStates;
class clsOpenLDVthread {
protected:
volatile eThreadStates meState;
CRITICAL_SECTION mCritControl; // critical section for thread control
char mszName[80];
HANDLE mhEvent, mhThread;
virtual bool blnStart() = 0;
public:
clsOpenLDVthread(LPCSTR pszName);
~clsOpenLDVthread();
bool inline blnIsRunning();
bool inline blnIsStopped();
bool inline blnIsStopping();
bool inline blnIsStarting();
bool inline blnIsPausing();
bool inline blnIsPaused();
bool blnPause(bool blnState);
virtual bool blnStop();
};
clsOpenLDVthread::clsOpenLDVthread(LPCSTR pszName) : meState(eIdle)
, mhThread(NULL) {
::InitializeCriticalSection(&mCritControl); //Get a critical section
//Get a unique name for signaling event
sprintf(mszName, "%s%d", pszName, ::GetCurrentProcessId());
//Get the event object
mhEvent = ::CreateEvent(NULL, FALSE, FALSE, mszName);
}
clsOpenLDVthread::~clsOpenLDVthread() {
if ( blnIsPaused() ) {
blnPause(false);
}
if ( blnIsRunning() ) {
blnStop();
}
if ( mhEvent ) {
::CloseHandle(mhEvent);
mhEvent = NULL;
}
::DeleteCriticalSection(&mCritControl);
}
bool clsOpenLDVthread::blnIsPaused() {
return meState == ePaused;
}
bool clsOpenLDVthread::blnIsPausing() {
return meState == ePausing;
}
bool clsOpenLDVthread::blnIsRunning() {
return meState == eRunning;
}
bool clsOpenLDVthread::blnIsStarting() {
return meState == eStarted;
}
bool clsOpenLDVthread::blnIsStopped() {
return meState == eIdle;
}
bool clsOpenLDVthread::blnIsStopping() {
return meState == eTerminating;
}
bool clsOpenLDVthread::blnPause(bool blnState) {
bool blnResult = mhThread != NULL;
if ( blnResult ) {
if ( blnState ) {
unsigned uintCountDown = 10u;
if ( blnIsRunning() || blnIsPausing() ) {
meState = ePausing;
while( blnIsPausing() && -- uintCountDown ) {
::SetEvent(mhEvent);
//Give thread chance to run and pause
_sleep(751);
}
blnResult = blnIsPaused();
}
} else {
if ( blnIsPaused() ) {
meState = eRunning;
//this will need replacing...mhThread->ResumeThread();
}
blnResult = true;
}
}
return blnResult;
}
bool clsOpenLDVthread::blnStop() {
bool blnResult = meState == eIdle;
unsigned uintCountDown = 100u;
if ( blnIsPaused() ) {
blnPause(false);
}
if ( blnIsRunning() ) {
meState = eTerminating;
while( !blnIsStopped() && --uintCountDown ) {
if ( mhEvent ) {
::SetEvent(mhEvent);
}
//Give thread a change to run and terminate
_sleep(501);
}
blnResult = blnIsStopped();
mhThread = NULL;
}
return blnResult;
}
Finally a derived class that implements the thread class and provides the blnStart method:
class clsOpenLDVrdr : public clsOpenLDVthread {
public:
//Maximum size of uplink data per single transfer
static const unsigned mscuBuffersize;
private:
//The thread's main routine
static void msgReaderThread(LPVOID lpParam);
public:
clsOpenLDVrdr();
virtual ~clsOpenLDVrdr();
//Call this to start the thread, see clsOpenLDVthread for more operations
virtual bool blnStart();
};
const unsigned clsOpenLDVrdr::mscuBuffersize = MAX_OPENLDV_DATA;
clsOpenLDVrdr::clsOpenLDVrdr() : clsOpenLDVthread(_T("EvOpenLDVrdr")) {
}
clsOpenLDVrdr::~clsOpenLDVrdr() {
}
bool clsOpenLDVrdr::blnStart() {
bool blnResult = false;
if ( blnIsStopped() ) {
meState = eStarted;
//Create the thread
mhThread = (HANDLE)_beginthread(&clsOpenLDVrdr::msgReaderThread
,0, NULL);
blnResult = mhThread != NULL;
while( blnResult && (meState == eStarted) ) {
//Give the thread chance to start and initialize
_sleep(501);
}
}
return blnResult && (meState == eRunning);
}
void clsOpenLDVrdr::msgReaderThread(LPVOID lpParam) {
OutputDebugString("msgReaderThread\n");
}
An instance of the class clsOpenLDVrdr is created and the blnStart method called:
clsOpenLDVrdr* pobjReader = new clsOpenLDVrdr();
pobjReader->blnStart();
I can see in the debugger that "blnStart" is being called and stepping into it everything is executed...but the thread never runs.
Also tried using _beginthreadex instead of _beginthread:
mhThread = (HANDLE)_beginthreadex(0, 0, pfnThread, pobParam, 0, 0);
No difference. There is some kind of incompatibility problem here as the simple example I created at the start of this post works and there isn't much difference between the two versions. Except maybe the way its used...the first simple example was created as a Windows console application. The project I'm having difficulty with is in a DLL.
I'm attaching to the DLL with the debugger and stepping through the code which works until it gets to the loop after the beginthread call then it just loops forever and never gets into the thread.
I just tried the following, adding a standalone thread with a standard C function:
unsigned __stdcall threadTest(void* pobjData) {
OutputDebugString("threadTest\n");
return 0;
}
I then modify the "_beginthread" call as follows:
mhThread = (HANDLE)_beginthreadex(0, 0, threadTest, pobjParam, 0, 0);
Sadly the result is the same, the threadTest function is not called. But a valid handle is returned.
Found this:
unable to call a thread in dll file
Looks interesting and may explain the strange behaviour I'm experiencing.
Solved...I didn't realise at first but for some reason the existing DLL had a call to:
DisableThreadLibraryCalls(hInstance);
This prevents the threads from running. Having commented this out everything now works.
Related
#include <windows.h>
#include <iostream>
#include <string>
#include <conio.h>
namespace jsw
{
namespace threading {
class auto_event {
public:
auto_event(): _event(CreateEvent(0, false, false, 0)) {}
BOOL wait(DWORD timeout = 1) const
{
return WaitForSingleObject(_event, timeout) == WAIT_OBJECT_0;
}
BOOL set() { return SetEvent(_event); }
private:
HANDLE _event;
};
class thread {
public:
static thread start(
LPTHREAD_START_ROUTINE fn, LPVOID args = 0,
DWORD state = 0, DWORD timeout = 1000)
{
return thread(CreateThread(0, 0, fn, args, state, 0), timeout);
}
static void sleep(DWORD milliseconds) { Sleep(milliseconds); }
static void exit(DWORD exitCode) { ExitThread(exitCode); }
public:
thread(HANDLE thread, DWORD timeout): _thread(thread), _timeout(timeout) {}
~thread() { CloseHandle(_thread); }
DWORD exit_code() const
{
DWORD exitCode = NO_ERROR;
GetExitCodeThread(_thread, &exitCode);
return exitCode;
}
HANDLE handle() const { return _thread; }
BOOL is_alive() const { return exit_code() == STILL_ACTIVE; }
DWORD join() { return WaitForSingleObject(_thread, _timeout); }
DWORD suspend() { return SuspendThread(_thread); }
DWORD resume() { return ResumeThread(_thread); }
BOOL abort(DWORD exitCode) { return TerminateThread(_thread, exitCode); }
private:
HANDLE _thread;
DWORD _timeout;
};
}
}
using namespace std;
DWORD WINAPI get_password(LPVOID args)
{
using namespace jsw::threading;
string *s = (string*)((LPVOID*)args)[0];
auto_event *e = (auto_event*)((LPVOID*)args)[1];
*s=getch();
e->set();
return NO_ERROR;
}
void time()
{
//...I'll get it
}
int main()
{
using namespace jsw::threading;
string password;
auto_event e;
LPVOID args[2] = {&password, &e};
thread worker = thread::start(get_password, args);
cout<<"time of game --> ";time();cout<<endl;
cout<<"Press one to go home"<<endl;
cout<<"Press two to drive your car"<<endl;
cout<<"Press three to visit near city"<<endl;
if (e.wait(1000))
{
if(password=="1") cout<<"House"<<endl;
else if(password=="2") cout<<"Car"<<endl;
else if(password=="3") cout<<"City"<<endl;
else cout<<"wrong option"<<endl;
}
else system("cls"); main();
return 0;
}
When the second on the clock changes and I select an option in the menu, I have to click the button several times because the first time the program does not load it. When starting the program, it loads correctly, but after a second, when the program uses else, I have to click the button several times.
(I need this procedure to change time with passing seconds in the program)
looking for a time limited cin I just found this code "namespace jsw" and "DWORD WINAPI". It works, because when the time is up, the program redisplays the menu with the changed time, but when retrieving a key there is a problem.
(Note before starting: Although my question is general, my code needs to compile with legacy Visual Studio 2008 MFC application and has to use MFC or win32 synchronization, please avoid answers using ie boost or c++ 11)
I am trying to implement a Thread Safe Pipe (A Queue with a single reader and a single writer), I did the following:
template<class T>
class CMultiThreadPipe {
private:
HANDLE hSemaphore, hTerminateEvent1, hTerminateEvent2;
CRITICAL_SECTION listMutex;
CList<T*, T*> list;
public:
CMultiThreadPipe() {
InitializeCriticalSection(&listMutex);
hSemaphore = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
hTerminateEvent1 = ::CreateEvent(NULL, TRUE, FALSE, NULL);
hTerminateEvent2 = ::CreateEvent(NULL, TRUE, FALSE, NULL);
}
// pdata must be allocated with new. The dequeueing thread will delete it
void Enqueue(T* pdata) {
EnterCriticalSection(&listMutex);
list.AddHead(pdata);
LeaveCriticalSection(&listMutex);
ReleaseSemaphore(hSemaphore, 1, NULL);
}
// if Dequeue returns null it means the pipe was destroyed and no further queue method calls are legal
// Dequeue caller is responsible to delete the returned instance
T* Dequeue()
{
HANDLE handles[] = { hTerminateEvent1, hSemaphore };
DWORD waitRes = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
if (waitRes==WAIT_OBJECT_0) {
SetEvent(hTerminateEvent2);
return NULL; // terminated
}
EnterCriticalSection(&listMutex);
T* elem = list.RemoveTail();
LeaveCriticalSection(&listMutex);
return elem; // handler must delete item
}
void Destroy() {
SetEvent(hTerminateEvent1);
WaitForSingleObject(hTerminateEvent2, INFINITE);
EnterCriticalSection(&listMutex);
POSITION pos = list.GetHeadPosition();
for (int i = 0; i < list.GetCount(); i++) delete list.GetNext(pos);
LeaveCriticalSection(&listMutex);
DeleteCriticalSection(&listMutex);
CloseHandle(hSemaphore);
}
~CMultiThreadPipe() {
Destroy();
}
};
The code is used like this:
class QueueData {
public:
QueueData(int i) : m_data(i) {};
int m_data;
};
UINT DequeueThreadProc(LPVOID dummy);
CMultiThreadedPipe<QueueData>* pPipe = NULL;
void main() {
pPipe = new CMultiThreadedPipe<QueueData>();
start new thread running DequeueThreadProc
int counter=0;
for (int counter=0; counter<10; counter++)
{
pPipe->Enqueue(new QueueData(counter));
Sleep(300);
}
delete pPipe;
}
UINT DequeueThreadProc(LPVOID ignore)
{
QueueData* queueData;
while ((queueData = pPipe->Dequeue()) != NULL) {
delete queueData;
Sleep(1000);
};
return 0;
}
The issue I have is with termination, in the above implementation, when the pipe is destroyed (always by the enqueing thread) it is waiting for the dequeing thread to know that it terminated before deleting the queue. It has to do that to prevent a situation where the dequeing thread tries to dequeue after the pipe is destroyed.
If the dequeing thread does not keep calling dequeue the first thread will hang in the destructor, also if the dequeing thread waits a long time between calls to dequeue the destructor of the first thread will get stuck there accordingly.
I read various posts about it none mentions safe destruction. Any help appreciated !
for safe destruction object, which accessed from multiple threads you need use reference counting on it. before pass object pointer to new thread - you increment reference on object. when thread no more using object, or if create thread fail, you decrement reference count. when last reference on object released - you can safe call destructor for object. and you not need here wait for any threads.
also for implement such queue - in windows exist special object - named I/O Completion Ports in user space (in kernel space in know as KQUEUE). with this object - implementation will be more efficient and simply - you not need manage self list (CList in your code), synchronize access to it - all this will be done in kernel space for you (PostQueuedCompletionStatus -> KeInsertQueue, GetQueuedCompletionStatus -> KeRemoveQueue). you need create only iocp, (kqueue) object.
class CMultiThreadPipe {
public:
class __declspec(novtable) QueueData {
public:
virtual void ProcessItem() = 0;
virtual ~QueueData()
{
DbgPrint("%x: %s<%p>\n", GetCurrentThreadId(), __FUNCTION__, this);
}
QueueData()
{
DbgPrint("%x: %s<%p>\n", GetCurrentThreadId(), __FUNCTION__, this);
}
};
private:
HANDLE _hIOCP;
LONG _dwRef;
ULONG _nThreads;
void DequeueThreadProc()
{
ULONG NumberOfBytesTransferred;
QueueData* pData;
OVERLAPPED* pOverlapped;
while (GetQueuedCompletionStatus(_hIOCP,
&NumberOfBytesTransferred,
(ULONG_PTR*)&pData,
&pOverlapped, INFINITE))
{
if (pData)
{
pData->ProcessItem();
}
else
{
break;
}
}
Release();
}
__declspec(noreturn) static DWORD CALLBACK _DequeueThreadProc(PVOID pThis)
{
reinterpret_cast<CMultiThreadPipe*>(pThis)->DequeueThreadProc();
FreeLibraryAndExitThread((HMODULE)&__ImageBase, 0);
}
~CMultiThreadPipe()
{
if (_hIOCP)
{
CloseHandle(_hIOCP);
}
}
public:
CMultiThreadPipe() : _dwRef(1), _hIOCP(0)
{
}
void AddRef()
{
InterlockedIncrement(&_dwRef);
}
void Release()
{
if (!InterlockedDecrement(&_dwRef))
{
delete this;
}
}
ULONG Create(DWORD NumberOfDequeueThreads)
{
if (_hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, NumberOfDequeueThreads))
{
ULONG n = 0;
do
{
HMODULE hModule;
if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (PCWSTR)_DequeueThreadProc, &hModule))
{
AddRef();
if (HANDLE hThread = CreateThread(0, 0, _DequeueThreadProc, this, 0, 0))
{
CloseHandle(hThread);
n++;
}
else
{
Release();
FreeLibrary(hModule);
}
}
} while (--NumberOfDequeueThreads);
_nThreads = n;
return n ? NOERROR : ERROR_GEN_FAILURE;
}
return GetLastError();
}
ULONG Enqueue(QueueData* pData)
{
return PostQueuedCompletionStatus(_hIOCP, 0, (ULONG_PTR)pData, 0) ? NOERROR : GetLastError();
}
void Destroy()
{
if (ULONG n = _nThreads)
{
do
{
PostQueuedCompletionStatus(_hIOCP, 0, 0, 0);
} while (--n);
}
}
};
and usage:
class QueueData : public CMultiThreadPipe::QueueData
{
int m_data;
virtual void ProcessItem()
{
DbgPrint("%x: %s<%p>(%u)\n", GetCurrentThreadId(), __FUNCTION__, this, m_data);
delete this;
}
public:
QueueData(int i) : m_data(i) {};
};
void testQueue()
{
if (CMultiThreadPipe* pPipe = new CMultiThreadPipe)
{
if (pPipe->Create(8) == NOERROR)
{
int n = 64;
do
{
if (QueueData* pData = new QueueData(n))
{
if (pPipe->Enqueue(pData))
{
delete pData;
}
}
} while (--n);
pPipe->Destroy();
}
pPipe->Release();
}
}
note with such CMultiThreadPipe implementations - you not need wait when working threads exit. even if your code inside dll and you unload dll - you not need wait. every thread have own reference for object and module. and release it on exit
In the following code, I have a simple server that sends a message to all clients 2 times a second, and another message 8-10 times a minute.
The problem is I am getting an error at runtime:
access violation at 00479740 read address FFFFFFD0
But only in a few systems, and only 1 or 2 times a day. This software works about 10 hours a day.
I have tried to use similar code with the ICS library and is seems to work well.
What's wrong in this code? Is there a better way to code it?
void __fastcall TDataNet::DataModuleCreate(TObject *Sender)
{
listaClient= new TThreadList();
psTx= new TStringList();
psRx= new TStringList();
}
void __fastcall TDataNet::DataModuleDestroy(TObject *Sender)
{
IdTCPServer1->Active= false;
listaClient->Free();
delete psTx;
delete psRx;
}
void __fastcall TDataNet::Send( TStrings *ps, TIdContext *AContext)
{
TList *lista;
static int cntSend= 0;
try
{
lista= listaClient->LockList();
if( AContext != NULL )
{
AContext->Connection->IOHandler->Write( ps, true, TIdTextEncoding_UTF8);
}
else
{
for( int i=0; i < lista->Count; i++ )
((TDatiClient*)lista->Items[i])->pThread->Connection->IOHandler->Write( ps, true, TIdTextEncoding_UTF8);
}
}
__finally
{
listaClient->UnlockList();
}
}
void __fastcall TDataNet::SetCambioPilota( void)
{
unsigned short hh, mm, ss, ms, hh1, mm1, ss1, ms1;
unsigned short hh2, mm2, ss2, ms2, hh3, mm3, ss3, ms3;
unsigned short hh4, mm4, ss4, ms4, dd4;
unsigned short hh5, mm5, ss5, ms5, dd5;
TStrings *ps;
UnicodeString s;
try
{
ps= psTx;
ps->Clear();
s= "<CAMBIO_PILOTA>";
ps->Add( s);
for( int i=0; i < MAX_PILOTI; i++ )
{
s.sprintf( L"<Pilota%02x= I%x,\"A%s\",\"C%s\",\"F%s\",f%x>",
i+1, gara.pilota[i].idnome,
gara.pilota[i].nome.c_str(), gara.pilota[i].nick.c_str(),
gara.pilota[i].nomeTeam.c_str(), gara.pilota[i].idPilotaT );
ps->Add( s);
}
s= "<END_CAMBIO_PILOTA>";
ps->Add( s);
Send( ps );
}
catch(...){}
}
void __fastcall TDataNet::SetDatiGara( void)
{
TStrings *ps;
UnicodeString s;
try
{
ps= psTx;
ps->Clear();
s= "<DATI_GARA>";
ps->Add( s);
s.sprintf( L"<eve=%d,A%x,B%x,C%x,D%x,E%x,F%x,G%x,H%x,I%x,J%x,K%x>", DataB->GetEventoInCorso().idEvento,
DataB->GetEventoInCorso().numEvento, DataB->GetEventoInCorso().subEvento,
DataB->GetNextEvento().idEvento, DataB->GetNextEvento().numEvento, DataB->GetNextEvento().subEvento,
gara.tkTempo, gara.tkDurata - gara.tkTempo,
gara.laps, gara.gDurata > 0 ? (gara.gDurata - gara.laps):0, gara.flInCorso ? (gara.gDurata > 0 ? 2:1):0,
gara.flFineGara );
ps->Add( s);
s= "<END_DATI_GARA>";
ps->Add( s);
Send( ps );
}
catch(...){}
}
void __fastcall TDataNet::Timer1Timer(TObject *Sender)
{
Timer1->Enabled= false;
SetDatiGara();
Timer1->Enabled= true;
}
void __fastcall TDataNet::IdTCPServer1Connect(TIdContext *AContext)
{
TDatiClient* dati;
dati= new TDatiClient;
dati->pThread= AContext;
AContext->Connection->IOHandler->ReadTimeout= 200;
AContext->Data= (TObject*)dati;
try
{
TList* lista;
lista= listaClient->LockList();
lista->Add( dati);
connessioni= lista->Count;
if( FmainWnd )
PostMessage( FmainWnd, WM_EVENTO_TCP, ID_CONNESSO, lista->Count);
int idEvento= DataB->GetEventoInCorso().idEvento;
if( idEvento )
SetCambioStato( idEvento, STATO_EVENTO_START, AContext);
}
__finally
{
listaClient->UnlockList();
}
}
void __fastcall TDataNet::IdTCPServer1Disconnect(TIdContext *AContext)
{
TDatiClient* dati;
dati= (TDatiClient*)AContext->Data;
AContext->Data= NULL;
try
{
listaClient->Remove( dati);
TList* lista;
lista= listaClient->LockList();
connessioni= lista->Count;
if( FmainWnd )
PostMessage( FmainWnd, WM_EVENTO_TCP, ID_DISCONNESSO, lista->Count);
}
__finally
{
listaClient->UnlockList();
}
delete dati;
}
void __fastcall TDataNet::IdTCPServer1Execute(TIdContext *AContext)
{
Sleep( 100);
try
{
AContext->Connection->IOHandler->ReadStrings( psRx, -1);
if( psRx->Count >= 2 && psRx->Strings[0] == "<LAST_MINUTE>" && psRx->Strings[psRx->Count-1] == "<END_LAST_MINUTE>" )
{
psRx->Delete(0);
psRx->Delete(psRx->Count-1);
if( FmainWnd )
SendMessage( FmainWnd, WM_EVENTO_TCP, ID_LAST_MINUTE, (unsigned int)psRx);
}
psRx->Clear();
}
catch( ...) {}
AContext->Connection->CheckForGracefulDisconnect();
}
The error message means you are accessing something that is -48 bytes offset from a NULL pointer. I see all kinds of problems with this code, the least of which is that you are accessing things in a thread-unsafe manner, so you have race conditions that could corrupt memory, amongst other possible issues. For example, your OnExecute event handler is not protecting the psRx object from concurrent access, so multiple clients could populate it with data at the exact same time, corrupting its contents.
TIdTCPServer is a multi-threaded component, its events are fired in the context of worker threads, not the main UI thread, so your event handlers MUST use thread-safe coding.
Besides, what you are doing is not the safest way to handle asynchronous communications with TIdTCPServer anyway. I would suggest something more like the following instead:
class TDatiClient : public TIdServerContext
{
public:
TIdThreadSafeObjectList *Queue;
bool QueueHasObjects;
__fastcall TDatiClient(TIdTCPConnection *AConnection, TIdYarn *AYarn, TThreadList* AList = NULL)
: TIdServerContext(AConnection, AYarn, AList)
{
Queue = new TIdThreadSafeObjectList;
}
__fastcall ~TDatiClient()
{
delete Queue;
}
void __fastcall Send(TStrings *ps)
{
TStringList *toSend = new TStringList;
try
{
toSend->Assign(ps);
TList *lista = Queue->LockList();
try
{
lista->Add(toSend);
QueueHasObjects = true;
}
__finally
{
Queue->UnlockList();
}
}
catch (const Exception &)
{
delete toSend;
}
}
};
void __fastcall TDataNet::TDataNet(TComponent *Owner)
: TDataModule(Owner)
{
// this must be set before you activate the server...
IdTCPServer1->ContextClass = __classid(TDatiClient);
// do this at runtime instead of design-time so
// ContextClass can be set first...
IdTCPServer1->Active = true;
}
void __fastcall TDataNet::~TDataNet()
{
IdTCPServer1->Active = false;
}
void __fastcall TDataNet::Send(TStrings *ps, TIdContext *AContext)
{
static int cntSend = 0;
TList *lista = IdTCPServer1->Contexts->LockList();
try
{
if (AContext)
{
// make sure the client is still in the list...
if (lista->IndexOf(AContext) != -1)
static_cast<TDatiClient*>(AContext)->Send(ps);
}
else
{
for (int i = 0; i < lista->Count; ++i)
static_cast<TDatiClient*>(static_cast<TIdContext*>(lista->Items[i]))->Send(ps);
}
}
__finally
{
IdTCPServer1->Contexts->UnlockList();
}
}
void __fastcall TDataNet::SetCambioPilota()
{
UnicodeString s;
try
{
TStringList *ps = new TStringList;
try
{
s = _D("<CAMBIO_PILOTA>");
ps->Add(s);
for (int i = 0; i < MAX_PILOTI; ++i)
{
s.sprintf( _D("<Pilota%02x= I%x,\"A%s\",\"C%s\",\"F%s\",f%x>),
// TODO: if SetCambioPilota() is ever called in a worker thread,
// make sure these values are accessed in a thread-safe manner!
i+1, gara.pilota[i].idnome,
gara.pilota[i].nome.c_str(), gara.pilota[i].nick.c_str(),
gara.pilota[i].nomeTeam.c_str(), gara.pilota[i].idPilotaT);
ps->Add(s);
}
s = _D("<END_CAMBIO_PILOTA>");
ps->Add(s);
Send(ps);
}
__finally
{
delete ps;
}
}
catch (const Exception &)
{
}
}
void __fastcall TDataNet::SetDatiGara()
{
UnicodeString s;
try
{
TStringList *ps = new TStringList;
try
{
s = _D("<DATI_GARA>");
ps->Add(s);
s.sprintf( _D("<eve=%d,A%x,B%x,C%x,D%x,E%x,F%x,G%x,H%x,I%x,J%x,K%x>"),
// TODO: if SetDatiGara() is ever called in a worker thread,
// make sure these values are accessed in a thread-safe manner!
DataB->GetEventoInCorso().idEvento,
DataB->GetEventoInCorso().numEvento, DataB->GetEventoInCorso().subEvento,
DataB->GetNextEvento().idEvento, DataB->GetNextEvento().numEvento, DataB->GetNextEvento().subEvento,
gara.tkTempo, gara.tkDurata - gara.tkTempo, gara.laps,
(gara.gDurata > 0) ? (gara.gDurata - gara.laps) : 0,
gara.flInCorso ? ((gara.gDurata > 0) ? 2 : 1) : 0,
gara.flFineGara);
ps->Add(s);
s = _D("<END_DATI_GARA>");
ps->Add(s);
Send(ps);
}
__finally
{
delete ps;
}
}
catch (const Exception &)
{
}
}
void __fastcall TDataNet::Timer1Timer(TObject *Sender)
{
Timer1->Enabled = false;
SetDatiGara();
Timer1->Enabled = true;
}
void __fastcall TDataNet::IdTCPServer1Connect(TIdContext *AContext)
{
TDatiClient* dati = static_cast<TDatiClient*>(AContext);
AContext->Connection->IOHandler->DefStringEncoding = TIdTextEncoding_UTF8;
TList* lista = IdTCPServer1->Contexts->LockList();
try
{
// TODO: this event is fired in a worker thread, so make sure
// that connessioni, DataB, and SetCambioStato() are all being
// accessed in a thread-safe manner!
int connessioni = lista->Count;
if (FmainWnd)
PostMessage(FmainWnd, WM_EVENTO_TCP, ID_CONNESSO, connessioni);
int idEvento = DataB->GetEventoInCorso().idEvento;
if (idEvento)
SetCambioStato(idEvento, STATO_EVENTO_START, AContext);
}
__finally
{
IdTCPServer1->Contexts->UnlockList();
}
}
void __fastcall TDataNet::IdTCPServer1Disconnect(TIdContext *AContext)
{
TDatiClient* dati = static_cast<TDatiClient*>(AContext);
TList* lista = IdTCPServer1->Contexts->LockList();
try
{
int connessioni = lista->Count - 1;
if (FmainWnd)
PostMessage(FmainWnd, WM_EVENTO_TCP, ID_DISCONNESSO, connessioni);
}
__finally
{
IdTCPServer1->Contexts->UnlockList();
}
}
void __fastcall TDataNet::IdTCPServer1Execute(TIdContext *AContext)
{
TDatiClient* dati = static_cast<TDatiClient*>(AContext);
TStringList *ps;
if (dati->QueueHasObjects)
{
TObjectList *objs = new TObjectList(false);
try
{
TList *lista = dati->Queue->LockList();
try
{
objs->Assign(lista);
lista->Clear();
objs->OwnsObjects = true;
}
__finally
{
dati->QueueHasObjects = (lista->Count > 0);
dati->Queue->UnlockList();
}
for (int i = 0; i < objs->Count; ++i)
{
ps = static_cast<TStringList*>(objs->Items[i]);
AContext->Connection->IOHandler->Write(ps, true);
}
}
__finally
{
delete objs;
}
}
if (AContext->Connection->IOHandler->InputBufferIsEmpty())
{
AContext->Connection->IOHandler->CheckForDataOnSource(200);
if (AContext->Connection->IOHandler->InputBufferIsEmpty())
{
AContext->Connection->IOHandler->CheckForDisconnect();
return;
}
}
ps = new TStringList;
try
{
AContext->Connection->IOHandler->ReadStrings(ps, -1);
if ((ps->Count >= 2) && (ps->Strings[0] == _D("<LAST_MINUTE>")) && (ps->Strings[ps->Count-1] == _D("<END_LAST_MINUTE>")))
{
ps->Delete(0);
ps->Delete(ps->Count-1);
if (FmainWnd)
SendMessage(FmainWnd, WM_EVENTO_TCP, ID_LAST_MINUTE, reinterpret_cast<LPARAM>(ps));
}
}
__finally
{
delete ps;
}
}
Okay, so I've an assignment with threads.I'm suppose to change the current running threads each period of time, let's say a second. First of all I've created a Thread class:
typedef unsigned long address_t;
#define JB_SP 6
#define JB_PC 7
#define STACK_SIZE (4096)
using namespace std;
class Thread{
public:
enum State{
BLOCKED,
READY,
RUNNING
};
Thread(int tid, void(*f)(void), int stack_size) :
tid(tid), stack_size(stack_size){
address_t sp, pc;
sp = (address_t)stack + STACK_SIZE - sizeof(address_t);
pc = (address_t)f;
sigsetjmp(env, 1);
(env->__jmpbuf)[JB_SP] = translate_address(sp);
(env->__jmpbuf)[JB_PC] = translate_address(pc);
sigemptyset(&env->__saved_mask);
state = READY;
quantums = 0;
}
Thread (){}
address_t translate_address(address_t addr)
{
address_t ret;
asm volatile("xor %%fs:0x30,%0\n"
"rol $0x11,%0\n"
: "=g" (ret)
: "0" (addr));
return ret;
}
State get_state() const
{
return state;
}
void set_state(State state1)
{
state = state1;
}
int get_id() const
{
return tid;
}
pthread_t& get_thread()
{
return thread;
}
sigjmp_buf& get_env()
{
return env;
}
void raise_quantums()
{
quantums ++;
}
int get_quantums()
{
return quantums;
}
int add_to_sync(int tid)
{
sync.push_back(tid);
}
bool appear_in_sync_list(int tid)
{
return (find(sync.begin(), sync.end(), tid) != sync.end());
}
private:
vector<int> sync;
int quantums;
State state;
char stack[STACK_SIZE];
sigjmp_buf env;
pthread_t thread;
int tid;
int stack_size;
};
I've this function which changes threads:
void running_thread(int sigNum)
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigprocmask(SIG_SETMASK, &set, NULL);
total_quantum ++;
if (currentThread.get_state() == Thread::RUNNING)
{
Thread& t = ready_threads.back();
ready_threads.pop_back();
currentThread.set_state(Thread::READY);
ready_threads.push_back(currentThread);
sigsetjmp(currentThread.get_env(), 1);
currentThread = t;
t.raise_quantums();
siglongjmp(currentThread.get_env(), 1);
}
if (currentThread.get_state() == Thread::BLOCKED)
{
Thread &t = ready_threads.back();
ready_threads.pop_back();
currentThread.set_state(Thread::BLOCKED);
blocked_threads.push_back(currentThread);
sigsetjmp(currentThread.get_env(), 1);
currentThread = t;
t.raise_quantums();
siglongjmp(currentThread.get_env(), 1);
}
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigprocmask(SIG_UNBLOCK, &set, NULL);
}
It actually doesn't matter what it do, my problem is that it isn't even called.
My program first call this function:
int clock_set()
{
int seconds = quantum / SECOND;
int usecs = quantum - seconds*SECOND;
timer.it_value.tv_sec = seconds;
timer.it_value.tv_usec = usecs;
timer.it_interval.tv_sec = seconds;
timer.it_interval.tv_usec = usecs;
struct sigaction sa;
sa.sa_handler = &running_thread;
if (sigaction(SIGVTALRM, &sa,NULL) < 0) {
cerr << "system error: sigaction error.";
return FAILURE;
}
// Start a virtual timer. It counts down whenever this process is executing.
if (setitimer (ITIMER_VIRTUAL, &timer, NULL)) {
cerr << "system error: setitimer error.";
return FAILURE;
}
return SUCCESS;
}
Basically I was trying to make running_thread get activate each second, so I Was using sigaction and sa_handler.
This is my main function:
int main()
{
uthread_init(1000000) // Initiliaze variable 'quantum' to be a second, this function also calls clock_set
uthread_spawn(&g); // Creating a thread object with function g inserting it to ready_threads vector and to threads vector
uthread_spawn(&f); // creating a thread object with function f inserting it to ready_threads vector and to threads vector
}
The vector "ready_threads" has 2 threads in it.
Why doesn't it call running_thread?
I have written a simple thread pool in c++ using posix, on Ubuntu, which compiles and runs as expected, when started from within Code::Blocks. However, when I execute the program from the terminal, it hangs after the first thread task completes.
Here is the code in the execute() function of the task object:
void TestTask::execute()
{
FILE* file;
std::string fname = "output";
char n = (char)m_id;
fname+=n;
fname+=".txt";
file = fopen(fname.c_str(), "w");
for (int i = 0; i < 10; i++)
{
fprintf(file,"Thread ID: %d, count : %d\n", m_id, i);
}
fclose(file);
}
As you can see, the code simply outputs some data to a seperate file for each thread.
I have also tried:
void TestTask::execute()
{
for (int i = 0; i < 10; i++)
{
printf("Thread ID: %d, count : %d\n", m_id, i);
}
}
As previously stated, both of these versions work perfectly when the project is built and run in code::blocks, but when the executable is run from a command line, it hangs.
Thread pool code:
ThreadPool::ThreadPool(int iNumThreads):mRunning(false), mShuttingDown(false)
{
mThreads.resize(iNumThreads);
if(iNumThreads > 0)
for (int i = 0; i < iNumThreads; i++)
{
pthread_create(&mThreads[i], NULL, ThreadPool::ThreadFunc,(void*) this);
}
pthread_mutex_init(&mMemLock, NULL); //mutex' are initialised unlocked.
}
void ThreadPool::stop()
{
pthread_mutex_lock(&mMemLock);
mRunning = false;
pthread_mutex_unlock(&mMemLock);
}
void ThreadPool::start()
{
//signal all threads to wake up and start extracting tasks to execute.
if(!mTasks.empty())
pthread_cond_broadcast(&mConditionSignal);
mRunning = true;
}
bool ThreadPool::shutDown()
{
//terminate all threads, regardless of status. Brute force approach, only to be used in race conditions or major errors.
for (size_t i = 0; i < mThreads.size();i++)
{
int err = pthread_cancel(mThreads[i]);
if(err != 0)
return false;
}
return true;
}
bool ThreadPool::shutDownClean()
{
//set flag and wait for all threads to terminate normally
mShuttingDown = true;
for(size_t i = 0; i < mThreads.size();i++)
{
pthread_join(mThreads[i], NULL);
}
return true;
}
bool ThreadPool::addTask(Task* pTask, bool start)
{
mTasks.push_back(pTask);
if(start)
{
mRunning = true;
pthread_cond_signal(&mConditionSignal);
}
return true;
//wake up a single thread to deal with a single task (first come, first served)
}
void ThreadPool::addCompleteTask(Task* pTask)
{
mCompletedTasks.push_back(pTask);
}
Task* ThreadPool::getNextCompletedTask()
{
Task* t = mCompletedTasks.front();
mCompletedTasks.pop_front();
return t;
}
Task* ThreadPool::getNextScheduledTask()
{
Task* t = mTasks.front();
mTasks.pop_front();
return t;
}
bool ThreadPool::isRunning()
{
return (mRunning);
}
ThreadPool::~ThreadPool()
{
if(!mShuttingDown)
shutDownClean();
mThreads.clear();
mTasks.clear();
mCompletedTasks.clear();
}
void* ThreadPool::ThreadFunc(void* ptr)
{
ThreadPool *pool = (ThreadPool*)ptr;
Task *task;
//infinite do nothing loop. The thread will spin it's wheels while it waits for work.
while(true)
{
pthread_mutex_lock(&pool->getMutex());
while(pool->isRunning() && !pool->hasCurrentTasks())
{
//wait on signal from pool to begin
pthread_cond_wait(&pool->getCondition(), &pool->getMutex());
}
//If the pool has tasks needing executed
if(pool->hasCurrentTasks())
{
//get the task and execute it, after unlocking the mutex
task = pool->getNextScheduledTask();
pthread_mutex_unlock(&pool->getMutex());
task->execute();
//if the task has return data, then add it to the list of completed tasks, for the main thread to evaluate
if(task->hasReturnData())
{
pthread_mutex_lock(&pool->getMutex());
pool->addCompleteTask(task);
pthread_mutex_unlock(&pool->getMutex());
}
//if not, we need not keep the task object any more
else
delete task;
}
else
{
//stop the pool running, and unlock the mutex
pool->stop();
pthread_mutex_unlock(&pool->getMutex());
}
if(pool->isShuttingDown())
{
break;
}
}
pthread_exit(NULL);
}
Here is the code from main.cpp:
int main(int argc, char** argv)
{
int numCores = sysconf(_SC_NPROCESSORS_ONLN);
ThreadPool* pool = new ThreadPool(numCores);
for (int i = 0; i < numCores; i++)
{
if(!pool->addTask(new TestTask(i)))
pool->shutDown();
}
pool->start();
if(!pool->shutDownClean())
return 1;
else
return 0;
}