-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy paththreadtools.cpp
150 lines (136 loc) · 3.4 KB
/
threadtools.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//----------------------------------------------------------------------------
#include "threadtools.h"
#include <memory>
//----------------------------------------------------------------------------
TEvent::TEvent(const bool aAutoReset, const bool aSignaled)
: AutoReset(aAutoReset),Signaled(aSignaled)
{
int st=pthread_cond_init(&mCondVar,NULL);
if (st)
throw TOSErr("pthread_cond_init failed.",st);
}
int TEvent::WaitFor(const unsigned int aTimeout_ms)
{
mCondMutex.Lock();
int st=0;
while (!Signaled)
{
if (!aTimeout_ms)
st=pthread_cond_wait(&mCondVar,mCondMutex.Handle());
else
{
struct timespec timeout,now;
timeout.tv_sec=aTimeout_ms/1000;
timeout.tv_nsec=(aTimeout_ms%1000)*1000000;
clock_gettime(CLOCK_REALTIME, &now);
ts_add(now, timeout);
st=pthread_cond_timedwait(&mCondVar,mCondMutex.Handle(),&now);
}
if (st) // Timeout oder Fehler
break;
}
if (AutoReset)
Signaled=false;
mCondMutex.Unlock();
return st;
}
void TEvent::SetEvent()
{
mCondMutex.Lock();
Signaled=true;
mCondMutex.Unlock();
if (!AutoReset)
{
int st=pthread_cond_broadcast(&mCondVar);
if (st)
throw TOSErr("pthread_cond_broadcast failed.",st);
}
else
{
int st=pthread_cond_signal(&mCondVar);
if (st)
throw TOSErr("pthread_cond_signal failed.",st);
}
}
void TEvent::ResetEvent()
{
mCondMutex.Lock();
Signaled=false;
mCondMutex.Unlock();
}
TEvent::~TEvent()
{
pthread_cond_destroy(&mCondVar);
}
// -----------------------------------------------------------
// -----------------------------------------------------------
// -----------------------------------------------------------
TThread::TThread()
: Handle(0)
, AlreadyRunning(false)
, ThreadResult(NULL)
, Status(0)
, SyncEvent(true,false)
{
TerminateRequested.Set(false);
Terminated.Set(false);
}
TThread::~TThread()
{
Terminate();
WaitFor();
}
void TThread::Run()
{
// Mehrfachen Run-Aufruf vermeiden
if (AlreadyRunning)
throw TPiShowErr("Thread of this object already running.");
AlreadyRunning=true;
Status=pthread_create(&Handle,NULL,ThreadFunc,this);
if (Status)
throw TOSErr("pthread_create failed.",Status);
// Warten, bis der Thread auch wirklich läuft...
SyncEvent.WaitFor();
}
void * TThread::ThreadFunc(void * aInstance)
{
TThread * MyInstance=static_cast<TThread*>(aInstance);
if (!MyInstance)
return NULL;
try
{
// Event setzten, Thread läuft
MyInstance->SyncEvent.SetEvent();
MyInstance->Execute();
MyInstance->Terminated.Set(true);
}
catch (std::exception & exc)
{
TCritGuard cg(MyInstance->mThreadErr.GetCritSec());
MyInstance->mThreadErr.GetUnsafe().reset(new TPiShowErr(exc.what()));
MyInstance->Terminated.Set(true);
}
catch (...)
{
TCritGuard cg(MyInstance->mThreadErr.GetCritSec());
MyInstance->mThreadErr.GetUnsafe().reset(new TPiShowErr("Unknown thread exception."));
MyInstance->Terminated.Set(true);
}
return NULL;
}
void TThread::Terminate()
{
TerminateRequested.Set(true);
printf("TerminateRequested gesetzt...\r\n");
}
void TThread::WaitFor()
{
if (Handle==0)
return;
// Erst nach dem Join werden die Thread-Ressourcen freigegeben!
// Jedem pthread_create ist ein entsprechendes Join gegeueberzustellen!
Status=pthread_join(Handle,&ThreadResult);
Handle=0;
//if (Status)
//throw TOSErr("pthread_join failed.",Status);
}