Posix多线程系列文章:
Linux 多线程Posix详解(一) : 线程的创建、等待、退出、取消与清理
Linux 多线程Posix详解(二) : 线程的同步与互斥
Linux 多线程Posix详解(三) : C++封装
一.前言
在使用多线程的过程中,如果每一次都需要使用 pthread_create
, pthread_cond_wait
这样的语句未免显得太过麻烦,于是将线程,锁进行封装,将其内部实现隐藏,需要的时候便能够直接使用。此篇文章主要封装三个类:
- 线程类
- 锁类
- 条件变量类
另外,此篇文章主要以面向对象
的方式进行封装,如果想使用多线程的基于对象
方式封装类,请访问我的github:
https://github.com/Worthy-Wang/MultiThread
头文件 Noncopyable.h 删除了拷贝复制函数 与 拷贝复制运算符,派生类继承后也将不能使用这两个函数。
Noncopyable.h
:
#pragma once
/*
不可拷贝基类:继承此基类的派生类将不能使用拷贝构造函数与拷贝赋值运算符
*/
namespace wd
{
class Noncopyable
{
protected:
Noncopyable() {}
~Noncopyable() {}
Noncopyable(const Noncopyable &lhs) = delete;
const Noncopyable &operator=(const Noncopyable &lhs) = delete;
};
} // namespace wd
二.线程类 Thread
线程类(虚基类):
调用start函数时,创建线程并调用静态threadFunc函数,在threadFunc函数中调用纯虚函数run,当有
派生类继承虚基类Thread的时候,只需要覆盖run函数即可创建线程运行run函数,非常方便。
Thread.h
:
#pragma once
#include <pthread.h>
#include <iostream>
#include "Noncopyable.h"
/*
*/
namespace wd
{
class Thread
: Noncopyable
{
public:
Thread();
virtual ~Thread();
void start();
void join();
private:
pthread_t _pid;
bool _isRunning;
virtual void run() = 0;
static void *threadFunc(void * arg);
};
} // namespace wd
Thread.cpp
:
#include "Thread.h"
namespace wd
{
Thread::Thread()
: _pid(0), _isRunning(false)
{
std::cout << "Thread()" << std::endl;
}
Thread::~Thread()
{
if (_isRunning)
{
if (pthread_detach(_pid))
{
perror("pthread_detach");
return;
}
_isRunning = false;
std::cout << "~Thread()" << std::endl;
}
}
void Thread::start()
{
if (!_isRunning)
{
if (pthread_create(&_pid, NULL, threadFunc, this))
{
perror("pthread_create");
return;
}
_isRunning = true;
}
}
void Thread::join()
{
if (_isRunning)
{
if (pthread_join(_pid, NULL))
{
perror("pthread_join");
return;
}
_isRunning = false;
std::cout << "join()" << std::endl;
}
}
void *Thread::threadFunc(void *arg)
{
Thread *p = static_cast<Thread *>(arg);
p->run();
return NULL;
}
} // namespace wd
利用任务类继承并重载run函数,就能够开启子线程并运行run函数,记得在编译的时候加上 -lpthread:
main.cpp
:
#include "Noncopyable.h"
#include "Thread.h"
#include <iostream>
#include <unistd.h>
#include <memory>
class MyThread
:public wd::Thread
{
private:
void run() override
{
while (1)
{
srand(time(NULL));
std::cout << rand() % 100 << std::endl;
sleep(1);
}
}
};
int main()
{
std::unique_ptr<MyThread> p1(new MyThread());
p1->start();
p1->join();
return 0;
}
二.锁类 MutexLock
封装锁类的时候需要注意一个问题:如果手动进行加解锁,那么如果因为系统中断导致无法解锁,那么就会形成死锁了。
在这里我们利用另一个类的生命周期来对锁进行加解锁。
MutexLockGuard?
在生成MutexLockGuard类对象之后,自动加锁,然后在语句块中执行完毕,调用析构函数的时候自动解锁,这样自动加解锁,避免了死锁的可能
MutexLock.h
:
#pragma once
#include <pthread.h>
#include <stdio.h>
#include "Noncopyable.h"
/*
封装mutex类,并创建类MutexLockGuard用来实现锁(MutexLock类加解锁不再对外开放),这样可以有效防止死锁
*/
namespace wd
{
class MutexLock
: Noncopyable
{
public:
MutexLock()
: _isLocking(false)
{
if (pthread_mutex_init(&_mutex, NULL))
{
perror("pthread_mutex_init");
return;
}
}
~MutexLock()
{
if (pthread_mutex_destroy(&_mutex))
{
perror("pthread_mutex_destroy");
return;
}
}
void lock()
{
if (pthread_mutex_lock(&_mutex))
{
perror("pthread_mutex_lock");
return;
}
_isLocking = true;
}
void unlock()
{
if (pthread_mutex_unlock(&_mutex))
{
perror("pthread_mutex_unlock");
return;
}
_isLocking = false;
}
bool isLocking() const { return _isLocking; }
pthread_mutex_t *getMutexPtr() { return &_mutex; }
private:
pthread_mutex_t _mutex;
bool _isLocking;
};
class MutexLockGuard
{
public:
MutexLockGuard(MutexLock &mutexlock)
: _mutexlock(mutexlock)
{
_mutexlock.lock();
}
~MutexLockGuard()
{
_mutexlock.unlock();
}
private:
MutexLock &_mutexlock;
};
} // namespace wd
三.条件变量类 Condition
Condition类需要和MutexLock类进行一起使用,这样才能完成线程的同步。
Condition.h
:
#pragma once
#include "Noncopyable.h"
#include "MutexLock.h"
namespace wd
{
class Condition
: Noncopyable
{
public:
Condition(MutexLock& mutexlock)
:_mutexlock(mutexlock)
{
if (pthread_cond_init(&_cond, NULL))
{
perror("pthread_cond_init");
return;
}
}
~Condition()
{
if (pthread_cond_destroy(&_cond))
{
perror("pthread_cond_destroy");
return;
}
}
void wait()
{
if (pthread_cond_wait(&_cond, _mutexlock.getMutexPtr()))
{
perror("pthread_cond_wait");
return;
}
}
void notify()
{
if (pthread_cond_signal(&_cond))
{
perror("pthread_cond_signal");
return;
}
}
void notifyAll()
{
if (pthread_cond_broadcast(&_cond))
{
perror("pthread_cond_broadcast");
return;
}
}
private:
pthread_cond_t _cond;
MutexLock& _mutexlock;
};
} // namespace wd