Linux多线程编程工具库liblmp_tool github: https://github.com/Dwyane05/liblmp_tool
Thread 类封装了原始 pthread_create等操作函数;内含同步工具和原子锁
头文件:
/*
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
* Thread.h
* Created on: May 30, 2019
* Author: cuiyongfei
*/
#ifndef LMP_TOOL_THREAD_H
#define LMP_TOOL_THREAD_H
#include "Atomic.h"
#include "CountDownLatch.h"
#include "Common.h"
#include
#include
#include
namespace lmp_tool
{
class Thread : noncopyable
{
public:
typedef std::function
explicit Thread(ThreadFunc, const string& name = string());
// FIXME: make it movable in C++11
~Thread();
void start();
int join(); // return pthread_join()
bool started() const { return started_; }
// pthread_t pthreadId() const { return pthreadId_; }
pid_t tid() const { return tid_; }
const string& name() const { return name_; }
static int numCreated() { return numCreated_.get(); }
private:
void setDefaultName();
bool started_;
bool joined_;
pthread_t pthreadId_;
pid_t tid_;
ThreadFunc func_;
string name_;
CountDownLatch latch_;
static AtomicInt32 numCreated_;
};
} // namespace lmp_tool
#endif // LMP_TOOL_THREAD_H
.cc文件
/*
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
* Thread.cc
* Created on: May 30, 2019
* Author: cuiyongfei
*/
#include "Thread.h"
#include "CurrentThread.h"
#include "Exception.h"
#include "Logging.h"
#include
#include
#include
#include
#include
#include
#include
#include
namespace lmp_tool
{
namespace detail
{
pid_t gettid()
{
return static_cast
}
void afterFork()
{
lmp_tool::CurrentThread::t_cachedTid = 0;
lmp_tool::CurrentThread::t_threadName = "main";
CurrentThread::tid();
// no need to call pthread_atfork(NULL, NULL, &afterFork);
}
class ThreadNameInitializer
{
public:
ThreadNameInitializer()
{
lmp_tool::CurrentThread::t_threadName = "main";
CurrentThread::tid();
pthread_atfork(NULL, NULL, &afterFork);
}
};
ThreadNameInitializer init;
struct ThreadData
{
typedef lmp_tool::Thread::ThreadFunc ThreadFunc;
ThreadFunc func_;
string name_;
pid_t* tid_;
CountDownLatch* latch_;
ThreadData(ThreadFunc func,
const string& name,
pid_t* tid,
CountDownLatch* latch)
: func_(std::move(func)),
name_(name),
tid_(tid),
latch_(latch)
{ }
void runInThread()
{
*tid_ = lmp_tool::CurrentThread::tid();
tid_ = NULL;
latch_->countDown();
latch_ = NULL;
lmp_tool::CurrentThread::t_threadName = name_.empty() ? "muduoThread" : name_.c_str();
::prctl(PR_SET_NAME, lmp_tool::CurrentThread::t_threadName);
try
{
func_();
lmp_tool::CurrentThread::t_threadName = "finished";
}
catch (const Exception& ex)
{
lmp_tool::CurrentThread::t_threadName = "crashed";
fprintf(stderr, "exception caught in Thread %s\n", name_.c_str());
fprintf(stderr, "reason: %s\n", ex.what());
fprintf(stderr, "stack trace: %s\n", ex.stackTrace());
abort();
}
catch (const std::exception& ex)
{
lmp_tool::CurrentThread::t_threadName = "crashed";
fprintf(stderr, "exception caught in Thread %s\n", name_.c_str());
fprintf(stderr, "reason: %s\n", ex.what());
abort();
}
catch (...)
{
lmp_tool::CurrentThread::t_threadName = "crashed";
fprintf(stderr, "unknown exception caught in Thread %s\n", name_.c_str());
throw; // rethrow
}
}
};
void* startThread(void* obj)
{
ThreadData* data = static_cast
data->runInThread();
delete data;
return NULL;
}
} // namespace detail
void CurrentThread::cacheTid()
{
if (t_cachedTid == 0)
{
t_cachedTid = detail::gettid();
t_tidStringLength = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid);
}
}
bool CurrentThread::isMainThread()
{
return tid() == ::getpid();
}
void CurrentThread::sleepUsec(int64_t usec)
{
struct timespec ts = { 0, 0 };
ts.tv_sec = static_cast
ts.tv_nsec = static_cast
::nanosleep(&ts, NULL);
}
AtomicInt32 Thread::numCreated_;
Thread::Thread(ThreadFunc func, const string& n)
: started_(false),
joined_(false),
pthreadId_(0),
tid_(0),
func_(std::move(func)),
name_(n),
latch_(1)
{
setDefaultName();
}
Thread::~Thread()
{
if (started_ && !joined_)
{
pthread_detach(pthreadId_);
}
}
void Thread::setDefaultName()
{
int num = numCreated_.incrementAndGet();
if (name_.empty())
{
char buf[32];
snprintf(buf, sizeof buf, "Thread%d", num);
name_ = buf;
}
}
void Thread::start()
{
assert(!started_);
started_ = true;
// FIXME: move(func_)
detail::ThreadData* data = new detail::ThreadData(func_, name_, &tid_, &latch_);
if (pthread_create(&pthreadId_, NULL, &detail::startThread, data))
{
started_ = false;
delete data; // or no delete?
LOG_SYSFATAL << "Failed in pthread_create";
}
else
{
latch_.wait();
assert(tid_ > 0);
}
}
int Thread::join()
{
assert(started_);
assert(!joined_);
joined_ = true;
return pthread_join(pthreadId_, NULL);
}
} // namespace lmp_tool
测试代码:
#include "Thread.h"
#include "CurrentThread.h"
#include
#include
#include
void mysleep(int seconds)
{
timespec t = { seconds, 0 };
nanosleep(&t, NULL);
}
void threadFunc()
{
printf("tid=%d\n", lmp_tool::CurrentThread::tid());
}
void threadFunc2(int x)
{
printf("tid=%d, x=%d\n", lmp_tool::CurrentThread::tid(), x);
}
void threadFunc3()
{
printf("tid=%d\n", lmp_tool::CurrentThread::tid());
mysleep(1);
}
class Foo
{
public:
explicit Foo(double x)
: x_(x)
{
}
void memberFunc()
{
printf("tid=%d, Foo::x_=%f\n", lmp_tool::CurrentThread::tid(), x_);
}
void memberFunc2(const std::string& text)
{
printf("tid=%d, Foo::x_=%f, text=%s\n", lmp_tool::CurrentThread::tid(), x_, text.c_str());
}
private:
double x_;
};
int main()
{
printf("pid=%d, tid=%d\n", ::getpid(), lmp_tool::CurrentThread::tid());
lmp_tool::Thread t1(threadFunc);
t1.start();
printf("t1.tid=%d\n", t1.tid());
t1.join();
lmp_tool::Thread t2(std::bind(threadFunc2, 42),
"thread for free function with argument");
t2.start();
printf("t2.tid=%d\n", t2.tid());
t2.join();
Foo foo(87.53);
lmp_tool::Thread t3(std::bind(&Foo::memberFunc, &foo),
"thread for member function without argument");
t3.start();
t3.join();
lmp_tool::Thread t4(std::bind(&Foo::memberFunc2, std::ref(foo), std::string("Cuiyongfei")));
t4.start();
t4.join();
{
lmp_tool::Thread t5(threadFunc3);
t5.start();
// t5 may destruct eariler than thread creation.
}
mysleep(2);
{
lmp_tool::Thread t6(threadFunc3);
t6.start();
mysleep(2);
// t6 destruct later than thread creation.
}
sleep(2);
printf("number of created threads %d\n", lmp_tool::Thread::numCreated());
}
结果: