
当你在开发这些场景时定会深有共鸣:
接下来我们直接进入正题:
所以我们做这样的设计:

这里设了模板参数是因为后期如果需要可以把func_t类型该为模板参数T让用户自己设定,为方便讲解后面的内容这里就暂时这么设定。
构造函数主要是对成员变量初始化,要注意这里需要对count做++。
thread(func_t fun)
: _fun(fun), _tid(0), _isdetach(false), _isrun(false)
{
_name = "thread-" + to_string(count);
count++;
}
~thread(){}pthread_create的使用
pthread_create声明如下:
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);pthread_create函数要求传入一个void *(*start_routine) (void *)类型的函数指针,但为了可以让用户更灵活的使用,我们可以在这里进行一下封装。也就是说希望用户想传什么类型的函数指针都行,那么可以单独设计这样一个函数,如下:
static void *Func(void *p)
{
thread<T> *self = (thread<T> *)p;
self->_isrun = true;
self->_fun();
return nullptr;
}这样在这个函数内再调用用户传入的函数_fun就行了。一个很巧妙的设计。
需要注意的几点:
Start实现如下:
bool Start()
{
if (_isrun)
return false;
int n = pthread_create(&_tid, nullptr, &Func, (void *)this);
if (n != 0)
{
perror("pthread_create");
return false;
}
else
return true;
}如果主线程不想再关心新线程的任务执行情况等,那么就可以设置新线程为分离状态,分离的新线程依旧在进程地址空间中,依旧与主线程共享资源,线程被分离后不用进join等待,join会失败。
pthread_detach的使用
pthread_detach声明如下:
int pthread_detach(pthread_t thread);Detach的实现:
bool Detach()
{
if (_isdetach) return false;
if (_isrun) pthread_detach(_tid);
_isdetach = true;
}线程被取消也就是线程退出,退出结果是-1。
pthread_cancel的使用
pthread_cancel声明:
int pthread_cancel(pthread_t thread);Cancel的实现:
bool Cancel()
{
if (!_isrun) return false;
pthread_cancel(_tid);
return true;
}线程等待和进程等待类似,为了获取到任务的完成情况。如果线程不进行等待就会造成内存泄漏。
pthread_join声明:
int pthread_join(pthread_t thread, void **retval);Join实现:
void *Join()
{
void *ret = nullptr;
pthread_join(_tid, &ret);
return ret;
}在 Linux 中,锁是一种互斥机制,用于控制多线程或多进程对共享资源的访问,避免竞态条件(Race Condition)和数据不一致问题。锁功能的介绍:
锁的核心作用

构造需要完成锁的初始化,使用pthread_mutex_init函数。
pthread_mutex_init的声明:
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);Mutex()实现:
Mutex()
{
pthread_mutex_init(&_mutex, nullptr);
}析构函数完成锁的释放
锁本身不会直接导致内存泄漏,但如果使用不当,可能会间接引发资源泄漏或死锁问题,所以我们需对锁进行destroy。
pthread_destroy的声明:
int pthread_mutex_destroy(pthread_mutex_t *mutex);~Mutex()实现
~Mutex()
{
pthread_mutex_destroy(&_mutex);
}pthread_mutex_lock的使用
pthread_mutex_lock的声明
int pthread_mutex_lock(pthread_mutex_t *mutex);void Lock()实现:
void Lock()
{
pthread_mutex_lock(&_mutex);
}pthread_mutex_unlock的使用
pthread_mutex_lock的声明
int pthread_mutex_unlock(pthread_mutex_t *mutex);void Unlock()实现:
void Unlock()
{
pthread_mutex_unlock(&_mutex);
}class LockGuard
{
public:
LockGuard(Mutex& lock)
: _lock(lock)
{
_lock.Lock();
}
~LockGuard()
{
_lock.Unlock();
}
private:
Mutex& _lock;
};RAII模式的锁好处在于在创建对象时自动加锁,在销毁时自动解锁,是全自动的,当临界区代码抛出异常时,RAII 对象的析构函数仍会执行,确保锁被释放,避免死锁。
但是在使用RAII模式的锁时要注意作用域的问题,确保锁在正确的作用域添加和释放。
条件变量是用来使线程或进程之间同步的,避免了一个锁被同一执行流循环式的重复占用。
它是怎么实现同步呢?其实是执行流之间互相“通知”,比如当某个条件不满足的时候,这个执行流就不要申请锁了,就在这里等着。等条件满足其它执行流会通知你。

条件变量的接口使用和锁的接口完全类似。
pthread_cond_init声明
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);pthread_cond_destroy声明
int pthread_cond_destroy(pthread_cond_t *cond);Cond与~Cond实现:
Cond()
{
pthread_cond_init(&_cond,nullptr);
}
~Cond()
{
pthread_cond_signal(&_cond);
}pthread_cond_wait的声明
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);pthread_cond_wait为什么要传入锁呢?其实是这样的,首先执行流申请了锁进入临界区后却因为某些条件不满足,无法往下执行,所以需要等待,但又不能一直霸占着锁,要不然就变成死锁了,所以需要把锁释放。
pthread_cond_wait函数的执行逻辑就是释放锁然后等待,当被唤醒时再次申请锁。
void Wait(Mutex mutex) 实现
void Wait(Mutex mutex)
{
pthread_cond_wait(&_cond,mutex.GetLock());
}pthread_cond_signal作用是唤醒一个正在等待的线程,声明如下:
int pthread_cond_signal(pthread_cond_t *cond);void Signal()实现
void Signal()
{
pthread_cond_signal(&_cond);
}pthread_cond_broadcast作用是唤醒所有正在等待的线程,声明如下:
void Broadcast()实现
void Broadcast()
{
pthread_cond_broadcast(&_cond);
}信号量的理解
当一个共享资源可以分为小块去访问,那么就可以使用一个计数器去记录这些小块资源,在被使用中的有多少未被使用的有多少,它相当于一种资源的预定机制。比如在生产者消费者模型中用环形队列做交易场所,那么信号量就可以来完成生产者和消费者之间需要的互斥和同步功能。
Sem(信号量)的封装几乎和Mutex和Cond一样,这里就不做详细讲解。
#include <semaphore.h>
#define DEF 1
class Sem
{
public:
Sem(int val = DEF)
{
sem_init(&_sem,0,val);
}
void P()
{
sem_wait(&_sem);
}
void V()
{
sem_post(&_sem);
}
~Sem()
{
sem_destroy(&_sem);
}
private:
sem_t _sem;
};1.Thread.hpp
#pragma once
#include <iostream>
#include <pthread.h>
#include <functional>
#include <string>
#include <errno.h>
using namespace std;
using func_t = std::function<void()>;
namespace my_thread
{
static int count = 1;
class thread
{
private:
static void *Func(void *p)
{
thread *self = (thread *)p;
self->_isrun = true;
self->_fun();
return nullptr;
}
public:
thread(func_t fun)
: _fun(fun), _tid(0), _isdetach(false), _isrun(false)
{
_name = "thread-" + to_string(count);
count++;
Start();
}
bool Start()
{
if (_isrun)
return false;
int n = pthread_create(&_tid, nullptr, &Func, (void *)this);
if (n != 0)
{
perror("pthread_create");
return false;
}
else
return true;
}
bool Cancel()
{
if(_isrun)
pthread_cancel(_tid);
else return false;
return true;
}
bool Detach()
{
if (_isdetach)
return false;
if(_isrun)
pthread_detach(_tid);
_isdetach = true;
}
void *Join()
{
void *ret = nullptr;
pthread_join(_tid, &ret);
return ret;
}
string getname()
{
return _name;
}
~thread()
{}
private:
func_t _fun;
pthread_t _tid;
string _name;
bool _isdetach;
bool _isrun;
};
}2.Mutex.hpp
#pragma once
#include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>
using namespace std;
namespace my_mutex
{
class Mutex
{
public:
Mutex()
{
pthread_mutex_init(&_mutex, nullptr);
}
void Lock()
{
pthread_mutex_lock(&_mutex);
}
void Unlock()
{
pthread_mutex_unlock(&_mutex);
}
pthread_mutex_t* GetLock()
{
return &_mutex;
}
~Mutex()
{
pthread_mutex_destroy(&_mutex);
}
private:
pthread_mutex_t _mutex;
};
class LockGuard
{
public:
LockGuard(Mutex& lock)
: _lock(lock)
{
_lock.Lock();
}
~LockGuard()
{
_lock.Unlock();
}
private:
Mutex& _lock;
};
}3.Cond.hpp
#pragma once
#include <iostream>
#include <pthread.h>
#include "mutex.hpp"
using namespace my_mutex;
namespace my_cond
{
class Cond
{
public:
Cond()
{
pthread_cond_init(&_cond,nullptr);
}
void Wait(Mutex mutex)
{
pthread_cond_wait(&_cond,mutex.GetLock());
}
void Signal()
{
pthread_cond_signal(&_cond);
}
void Broadcast()
{
pthread_cond_broadcast(&_cond);
}
~Cond()
{
pthread_cond_signal(&_cond);
}
private:
pthread_cond_t _cond;
};
}
class Cond
{
public:
Cond();
void Wait(Mutex mutex);
void Signal();
void Broadcast();
~Cond();
private:
pthread_cond_t _cond;
};4. Sem.hpp
#pragma once
#include <semaphore.h>
#define DEF 1
class Sem
{
public:
Sem(int val = DEF)
{
sem_init(&_sem,0,val);
}
void P()
{
sem_wait(&_sem);
}
void V()
{
sem_post(&_sem);
}
~Sem()
{
sem_destroy(&_sem);
}
private:
sem_t _sem;
};