版权声明:guojawee https://blog.csdn.net/weixin_36750623/article/details/84309778
(1) 线程:Thread、CurrentThread
Thread.h、Thread.cc代码解读
功能介绍:
- 创建线程时,把线程函数当作形参传递进去:muduo::Thread t(std::bind(threadFunc2, 42), “thread for free function with argument”);
说明:线程形参func_是void func()类型的,可以使用boost::bind进行适配 - 启动线程,使线程回调线程函数func_:t.start()
- 使线程不先退出:t.join
源代码分析:Thread类
class Thread : noncopyable
{
public:
typedef std::function<void ()> ThreadFunc; //线程函数类型
//创建线程时,形参:func是线程函数,当start()时,func()开始执行
explicit Thread(ThreadFunc func, const string& n)
: started_(false),joined_(false),pthreadId_(0),tid_(0),
func_(std::move(func)), //线程函数
name_(n),latch_(1)
{
setDefaultName();
}
~Thread();
void start() //最后调用了传进来的func()函数
{//调用顺序:start()-->pthread_create()-->startThread()-->runInThread()-->func_()
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 join();
bool started() const { return started_; }
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_;
};
测试代码 ./test/Thread_test.c
#include <muduo/base/Thread.h>
#include <muduo/base/CurrentThread.h>
#include <string>
#include <stdio.h>
#include <unistd.h>
void threadFunc()
{
printf("tid=%d\n", muduo::CurrentThread::tid());
}
void threadFunc2(int x)
{
printf("tid=%d, x=%d\n", muduo::CurrentThread::tid(), x);
}
class Foo
{
public:
explicit Foo(double x)
: x_(x)
{
}
void memberFunc()
{
printf("tid=%d, Foo::x_=%f\n", muduo::CurrentThread::tid(), x_);
}
void memberFunc2(const std::string& text)
{
printf("tid=%d, Foo::x_=%f, text=%s\n", muduo::CurrentThread::tid(), x_, text.c_str());
}
private:
double x_;
};
int main()
{
printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid());
//threadFunc无参,无需适配
muduo::Thread t1(threadFunc);
t1.start();
printf("t1.tid=%d\n", t1.tid());
t1.join();
//threadFunc一个参数,需适配
muduo::Thread t2(std::bind(threadFunc2, 42),
"thread for free function with argument");
t2.start();
printf("t2.tid=%d\n", t2.tid());
t2.join();
//Foo对象的成员函数memberFunc
Foo foo(87.53);
muduo::Thread t3(std::bind(&Foo::memberFunc, &foo),
"thread for member function without argument");
t3.start();
t3.join();
//Foo对象的成员函数memberFunc2
muduo::Thread t4(std::bind(&Foo::memberFunc2, std::ref(foo), std::string("Shuo Chen")));
t4.start();
t4.join();
printf("number of created threads %d\n", muduo::Thread::numCreated());
}
CurrentThread.h
namespace CurrentThread
{
# __thread修饰的变量是线程局部存储的,每个线程都有一份
__thread int t_cachedTid = 0; # 线程真实pid(tid)的缓存,是为
#了提高获取tid的效率,较少::syscall(SYS_gettid)系统调用的次数
__thread char t_tidString[32]; # tid的字符串表示形式
__thread int t_tidStringLength = 6;
__thread const char* t_threadName = "unknown"; #每个线程的名称
(2)互斥锁:MutexLock、MutexLockGuard
MutexLock
功能:对Linux C下的互斥锁Mutex进行了封装,功能一致
class CAPABILITY("mutex") MutexLock : noncopyable
{
private:
pthread_mutex_t mutex_;
pid_t holder_; //当前拥有该锁的真实的线程id
public:
MutexLock()
: holder_(0)
{
MCHECK(pthread_mutex_init(&mutex_, NULL));
}
~MutexLock()
{
assert(holder_ == 0);
MCHECK(pthread_mutex_destroy(&mutex_));
}
// must be called when locked, i.e. for assertion
bool isLockedByThisThread() const // 是否当前线程拥有该锁
{
return holder_ == CurrentThread::tid();
}
void assertLocked() const ASSERT_CAPABILITY(this)
{
assert(isLockedByThisThread());
}
// internal usage
void lock() ACQUIRE() //加锁
{
MCHECK(pthread_mutex_lock(&mutex_));
assignHolder();
}
void unlock() RELEASE()
{
unassignHolder();
MCHECK(pthread_mutex_unlock(&mutex_));
}
pthread_mutex_t* getPthreadMutex() /* non-const */
{
return &mutex_;
}
... ...
};
MutexLockGuard
与MutexLock不同点:当MutexLockGuard类型的锁对象被销毁时,将调用析构函数,导致加的锁将自动释放
class SCOPED_CAPABILITY MutexLockGuard : noncopyable
{
public:
explicit MutexLockGuard(MutexLock& mutex) ACQUIRE(mutex)
: mutex_(mutex) // 构造时,对mutex_加锁
{
mutex_.lock();
}
~MutexLockGuard() RELEASE() //析构时,对mutex_解锁
{
mutex_.unlock();
}
private:
MutexLock& mutex_;
};
// 宏:不允许定义一个匿名的MutexLockGuard对象
#define MutexLockGuard(x) error "Missing guard object name"
示例代码
#include <muduo/base/Mutex.h>
#include <muduo/base/Thread.h>
#include <muduo/base/Timestamp.h>
#include <vector>
#include <stdio.h>
using namespace muduo;
using namespace std;
MutexLock g_mutex;
vector<int> g_vec;
const int kCount = 10*1000*1000;
void threadFunc()
{
for (int i = 0; i < kCount; ++i)
{
MutexLockGuard lock(g_mutex); //构造函数中,加锁
g_vec.push_back(i);
} //函数退出,调用MutexLockGuard析构函数,解锁(因此不需要手动的解锁)
}
int main()
{
const int kMaxThreads = 8;
g_vec.reserve(kMaxThreads * kCount);
//单个线程不加锁
Timestamp start(Timestamp::now());
for (int i = 0; i < kCount; ++i)
{
g_vec.push_back(i);
}
printf("single thread without lock %f\n", timeDifference(Timestamp::now(), start));
//单个线程加锁
start = Timestamp::now();
threadFunc();
printf("single thread with lock %f\n", timeDifference(Timestamp::now(), start));
//分别创建1、2、3、4、5、6、7个线程,统计时间开销
for (int nthreads = 1; nthreads < kMaxThreads; ++nthreads)
{
std::vector<std::unique_ptr<Thread>> threads;
g_vec.clear();
start = Timestamp::now();
for (int i = 0; i < nthreads; ++i)
{
threads.emplace_back(new Thread(&threadFunc));
threads.back()->start();
}
for (int i = 0; i < nthreads; ++i)
{
threads[i]->join();
}
printf("%d thread(s) with lock %f\n", nthreads, timeDifference(Timestamp::now(), start));
}
}
(3) 条件变量:Condition、CountDownLatch
Condition
主要功能:对Linux C下的条件变量Condition进行了封装,功能一致
class Condition : noncopyable
{
private:
MutexLock& mutex_; // 条件变量要配合互斥锁一起使用
pthread_cond_t pcond_;
public:
explicit Condition(MutexLock& mutex)
: mutex_(mutex)
{
MCHECK(pthread_cond_init(&pcond_, NULL));
}
~Condition()
{
MCHECK(pthread_cond_destroy(&pcond_));
}
void wait()
{
MutexLock::UnassignGuard ug(mutex_);
MCHECK(pthread_cond_wait(&pcond_, mutex_.getPthreadMutex()));
}
// returns true if time out, false otherwise.
bool waitForSeconds(double seconds) // 调用了pthread_cond_timedwait
{
struct timespec abstime;
// FIXME: use CLOCK_MONOTONIC or CLOCK_MONOTONIC_RAW to prevent time rewind.
clock_gettime(CLOCK_REALTIME, &abstime);
const int64_t kNanoSecondsPerSecond = 1000000000;
int64_t nanoseconds = static_cast<int64_t>(seconds * kNanoSecondsPerSecond);
abstime.tv_sec += static_cast<time_t>((abstime.tv_nsec + nanoseconds) / kNanoSecondsPerSecond);
abstime.tv_nsec = static_cast<long>((abstime.tv_nsec + nanoseconds) % kNanoSecondsPerSecond);
MutexLock::UnassignGuard ug(mutex_);
return ETIMEDOUT == pthread_cond_timedwait(&pcond_, mutex_.getPthreadMutex(), &abstime);
}
void notify()
{
MCHECK(pthread_cond_signal(&pcond_));
}
void notifyAll()
{
MCHECK(pthread_cond_broadcast(&pcond_));
}
};
CountDownLatch
CountDownLatch类,对条件变量类进行了封装
- 使用条件变量Condition,可以使得线程阻塞在一个条件上
- 使用CountDownLatch,可以使得线程阻塞在count_变量是否为0上。那么,哪个线程将会阻塞在count!=0条件上呢?答案:调用wait()函数的线程
class CountDownLatch : noncopyable
{
private:
mutable MutexLock mutex_;
Condition condition_ ;
int count_ ;
public:
explicit CountDownLatch::CountDownLatch(int count)
: mutex_(),condition_(mutex_),count_(count)
{
}
//调用wait()函数的线程,当count_>0时将会阻塞在wait()函数处
void wait()
{
MutexLockGuard lock(mutex_);
while (count_ > 0)
{
condition_.wait();
}
}
void countDown()
{
MutexLockGuard lock(mutex_);
--count_;
if (count_ == 0)
{
condition_.notifyAll();
}
}
int getCount() const
{
MutexLockGuard lock(mutex_);
return count_;
}
};