📄 thread.cpp
字号:
/*
* thread.c: A simple thread base class
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: thread.c 1.45 2005/08/14 11:15:42 kls Exp $
*/
#include "..\stdafx.h"
#include "thread.h"
#include <malloc.h>
#include <stdarg.h>
#include "..\asprintf.h"
#include <sys/timeb.h>
#define DELTA_EPOCH_IN_USEC 11644473600000000Ui64
static unsigned __int64 filetime_to_unix_epoch (const FILETIME *ft)
{
unsigned __int64 res = (unsigned __int64) ft->dwHighDateTime << 32;
res |= ft->dwLowDateTime;
res /= 10; /* from 100 nano-sec periods to usec */
res -= DELTA_EPOCH_IN_USEC; /* from Win epoch to Unix epoch */
return (res);
}
int gettimeofday (struct timeval *tv, void *tz)
{
FILETIME ft;
unsigned __int64 tim;
if (!tv) {
errno = EINVAL;
return (-1);
}
GetSystemTimeAsFileTime (&ft);
tim = filetime_to_unix_epoch (&ft);
tv->tv_sec = (long) (tim / 1000000L);
tv->tv_usec = (long) (tim % 1000000L);
return (0);
}
//static bool GetAbsTime(struct timespec *Abstime, int MillisecondsFromNow)
//{
// struct timeval now;
// if (gettimeofday(&now, NULL) == 0) { // get current time
// now.tv_usec += MillisecondsFromNow * 1000; // add the timeout
// while (now.tv_usec >= 1000000) { // take care of an overflow
// now.tv_sec++;
// now.tv_usec -= 1000000;
// }
// Abstime->tv_sec = now.tv_sec; // seconds
// Abstime->tv_nsec = now.tv_usec * 1000; // nano seconds
// return true;
// }
// return false;
//}
static bool GetAbsTime(struct timespec *Abstime, int MillisecondsFromNow)
{
struct _timeb now;
const DWORD NANOSEC_PER_MILLISEC = 1000000;
_ftime(&now);
now.millitm += MillisecondsFromNow;
while (now.millitm >= 1000) {
now.time++;
now.millitm -= 1000;
}
Abstime->tv_sec = now.time; // seconds
Abstime->tv_nsec = now.millitm * NANOSEC_PER_MILLISEC; // nano seconds*/
return true;
}
// --- cCondWait -------------------------------------------------------------
cCondWait::cCondWait(void)
{
signaled = false;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
}
cCondWait::~cCondWait()
{
pthread_cond_broadcast(&cond); // wake up any sleepers
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
}
void cCondWait::SleepMs(int TimeoutMs)
{
cCondWait w;
w.Wait(max(TimeoutMs, 3)); // making sure the time is >2ms to avoid a possible busy wait
}
bool cCondWait::Wait(int TimeoutMs)
{
pthread_mutex_lock(&mutex);
if (!signaled) {
if (TimeoutMs) {
struct timespec abstime;
if (GetAbsTime(&abstime, TimeoutMs)) {
while (!signaled) {
if (pthread_cond_timedwait(&cond, &mutex, &abstime) == ETIMEDOUT)
break;
}
}
}
else
pthread_cond_wait(&cond, &mutex);
}
bool r = signaled;
signaled = false;
pthread_mutex_unlock(&mutex);
return r;
}
// --- cCondVar --------------------------------------------------------------
cCondVar::cCondVar(void)
{
pthread_cond_init(&cond, 0);
}
cCondVar::~cCondVar()
{
pthread_cond_broadcast(&cond); // wake up any sleepers
pthread_cond_destroy(&cond);
}
void cCondVar::Wait(cMutex &Mutex)
{
if (Mutex.locked) {
int locked = Mutex.locked;
Mutex.locked = 0; // have to clear the locked count here, as pthread_cond_wait
// does an implicit unlock of the mutex
pthread_cond_wait(&cond, &Mutex.mutex);
Mutex.locked = locked;
}
}
bool cCondVar::TimedWait(cMutex &Mutex, int TimeoutMs)
{
bool r = true; // true = condition signaled, false = timeout
if (Mutex.locked) {
struct timespec abstime;
if (GetAbsTime(&abstime, TimeoutMs)) {
int locked = Mutex.locked;
Mutex.locked = 0; // have to clear the locked count here, as pthread_cond_timedwait
// does an implicit unlock of the mutex.
if (pthread_cond_timedwait(&cond, &Mutex.mutex, &abstime) == ETIMEDOUT)
r = false;
Mutex.locked = locked;
}
}
return r;
}
void cCondVar::Broadcast(void)
{
pthread_cond_broadcast(&cond);
}
// --- cMutex ----------------------------------------------------------------
cMutex::cMutex(void)
{
locked = 0;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
pthread_mutex_init(&mutex, &attr);
}
cMutex::~cMutex()
{
pthread_mutex_destroy(&mutex);
}
void cMutex::Lock(void)
{
pthread_mutex_lock(&mutex);
locked++;
}
void cMutex::Unlock(void)
{
if (!--locked)
pthread_mutex_unlock(&mutex);
}
// --- cThread ---------------------------------------------------------------
cThread::cThread(const char *Description)
{
active = running = false;
childTid.p = 0;
childTid.x = 0;
childThreadId = 0;
description = NULL;
if (Description)
SetDescription("%s",Description);
}
cThread::~cThread()
{
Cancel(); // just in case the derived class didn't call it
free(description);
}
void cThread::SetDescription(const char *Description, ...)
{
free(description);
description = NULL;
if (Description) {
va_list ap;
va_start(ap, Description);
vasprintf(&description, Description, ap);
va_end(ap);
}
}
void *cThread::StartThread(cThread *Thread)
{
if (Thread->description)
printf("%s thread started (tid=%ld)\n", Thread->description, pthread_self());
Thread->Action();
if (Thread->description)
printf("%s thread ended (tid=%ld)\n", Thread->description, pthread_self());
Thread->running = false;
Thread->active = false;
return NULL;
}
bool cThread::Start(void)
{
if (!active) {
active = running = true;
if (pthread_create(&childTid, NULL, (void *(*) (void *))&StartThread, (void *)this) == 0) {
pthread_detach(childTid); // auto-reap
pthread_setschedparam(childTid, SCHED_RR, 0);
}
else {
active = running = false;
return false;
}
}
return true;
}
bool cThread::Active(void)
{
if (active) {
//
// Single UNIX Spec v2 says:
//
// The pthread_kill() function is used to request
// that a signal be delivered to the specified thread.
//
// As in kill(), if sig is zero, error checking is
// performed but no signal is actually sent.
//
int err;
if ((err = pthread_kill(childTid, 0)) != 0) {
if (err != ESRCH)
printf("ERROR (%s,%d)", __FILE__, __LINE__);
childTid.p = 0;
childTid.x = 0;
active = running = false;
}
else
return true;
}
return false;
}
void cThread::Cancel(int WaitSeconds)
{
running = false;
if (active) {
if (WaitSeconds > 0) {
for (time_t t0 = time(NULL) + WaitSeconds; time(NULL) < t0; ) {
if (!Active())
return;
cCondWait::SleepMs(10);
}
printf("ERROR: %s thread %d won't end (waited %d seconds) - canceling it...", description ? description : "", childThreadId, WaitSeconds);
}
pthread_cancel(childTid);
childTid.p = 0;
childTid.x = 0;
active = false;
}
}
// --- cMutexLock ------------------------------------------------------------
cMutexLock::cMutexLock(cMutex *Mutex)
{
mutex = NULL;
locked = false;
Lock(Mutex);
}
cMutexLock::~cMutexLock()
{
if (mutex && locked)
mutex->Unlock();
}
bool cMutexLock::Lock(cMutex *Mutex)
{
if (Mutex && !mutex) {
mutex = Mutex;
Mutex->Lock();
locked = true;
return true;
}
return false;
}
// --- cThreadLock -----------------------------------------------------------
cThreadLock::cThreadLock(cThread *Thread)
{
thread = NULL;
locked = false;
Lock(Thread);
}
cThreadLock::~cThreadLock()
{
if (thread && locked)
thread->Unlock();
}
bool cThreadLock::Lock(cThread *Thread)
{
if (Thread && !thread) {
thread = Thread;
Thread->Lock();
locked = true;
return true;
}
return false;
}
// --- cPipe -----------------------------------------------------------------
// cPipe::Open() and cPipe::Close() are based on code originally received from
// Andreas Vitting <Andreas@huji.de>
cPipe::cPipe(void)
{
pid = -1;
f = NULL;
}
cPipe::~cPipe()
{
Close();
}
bool cPipe::Open(const char *Command, const char *Mode)
{
int fd[2];
return false;
}
int cPipe::Close(void)
{
int ret = -1;
return ret;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -