【C++实现HTTP服务器项目记录】线程同步类

【C++实现HTTP服务器项目记录】线程同步类,第1张

文章目录

  • 一、互斥锁


  • 二、死锁

    • 1. 预防死锁
      • (1)破坏互斥条件
      • (2)破坏不剥夺条件
      • (3)破坏请求和保持条件
      • (4)破坏循环等待条件
    • 2. 避免死锁
    • 3. 解除死锁

  • 三、信号量


  • 四、条件变量


一、互斥锁

- 互斥锁是线程同步最常用的一种方式,可以解决多线程访问共享资源数据混乱的问题。


- 通过互斥锁可以锁定一个代码块,被锁定的这个代码块,所有的线程只能"顺序执行"。


- 但执行效率降低,默认情况下临界区是可以被多个线程并行处理的,现在只能串行处理。


- 一般情况下,每一个共享资源对应一个把互斥锁,锁的个数和线程的个数无关。


#include 
#include 

// 互斥锁
class locker
{
public:
    // 初始化互斥锁
    locker()
    {
        if (pthread_mutex_init(&m_mutex, NULL) != 0)
        {
            throw std::exception();
        }
    }
    // 释放互斥锁资源
    ~locker()
    {
        pthread_mutex_destroy(&m_mutex);
    }
    // 加锁
    // 若锁没有被锁定,此线程加锁成功,锁中记录该线程加锁成功。


// 若锁被锁定,其他线程会加锁失败,都会阻塞在这把锁上。


// 锁被解开后,阻塞在锁上的线程就解除阻塞,并且通过竞争的方式对锁进行加锁,没抢到锁的线程继续阻塞。


bool lock() { return pthread_mutex_lock(&m_mutex) == 0; } // 解锁 // 哪个线程加的锁,哪个线程才能解锁! bool unlock() { return pthread_mutex_unlock(&m_mutex) == 0; } // 获取互斥锁地址 pthread_mutex_t *get() { return &m_mutex; } private: // 互斥锁 pthread_mutex_t m_mutex; };


二、死锁 1. 预防死锁

- 死锁的产生必须满足四个必要条件:互斥条件、不剥夺条件、请求和保持条件、循环等待条件。


(1)破坏互斥条件
- 互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁。


- 解决方法:将临界资源改造为可共享使用的资源,如:SPOOLing技术。


- 缺点:一般情况下为了系统安全,必须保护这种互斥性,可行性不高。


(2)破坏不剥夺条件
- 不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放。


- 解决方法: 1. 申请的资源得不到满足时,立即释放拥有的所有资源。


2. 申请的资源被其他进程占用,考虑优先级由 *** 作系统剥夺资源。


- 缺点: 1. 实现复杂。


2. 释放已获得的资源可能造成前一阶段工作的失效。


3. 反复申请和释放资源会增加系统开销。


4. 可能导致进程饥饿。


(3)破坏请求和保持条件
- 请求和保持条件:进程已经保持至少一个资源,且又提出新的资源请求,而该资源又被其他进程占有,此时请求进程被阻塞,但又对已有的资源保持不放。


- 解决方法:进程在运行前,就一次分配所有需要的资源。


资源未满足前不能运行,运行后这些资源就一直归它所有。


- 缺点: 1. 有些资源可能只需要用很短的时间,如果进程的整个运行期间都一直保持着所有资源,资源利用率极低。


2. 可能导致进程饥饿。


(4)破坏循环等待条件
- 循环等待条件:存在进程资源的循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求。


- 解决方法:给系统中的资源编号,规定每个进程必须按编号递增的顺序请求资源,编号相同的资源一次申请完。


- 原理:在任何一个时刻,总有一个进程拥有的资源编号是最大的,那么这个进程申请之后的资源必然畅通无阻。


- 缺点: 1. 不方便增加新的设备,因为可能需要重新编号。


2. 进程实际使用资源的顺序可能和编号递增顺序不一致,导致资源浪费。


3. 编程不方便。


2. 避免死锁

银行家算法与安全性算法

3. 解除死锁
- 死锁进程:死锁检测算法化简资源分配图后,还连着边的那些进程就是死锁进程。


- 解决方法 1. 资源剥夺法:挂起某些死锁进程,将其资源分配给其他的死锁进程,应防止被挂起的进程长时间得不到资源而饥饿。


2. 撤销进程法:强制撤销死锁进程,剥夺这些进程的资源。


若有些进程可能已经运行了很长时间,被终止功亏一篑。


3. 进程回退法:让死锁进程回退到足以避免死锁的地步。



三、信号量

- 信号量不一定是锁定某一个资源,也可以是流程上的概念。


一个线程完成了某一个动作就通过信号量通知别的线程,别的线程再进行某些动作。


- 信号量主要阻塞线程,不能完全保证线程安全,如果要保证线程安全,需要信号量和互斥锁一起使用。


#include 
#include 

// 信号量
class sem
{
public:
    // 初始化信号量
    sem()
    {
        // 用于线程同步,当前信号量拥有的资源数为0
        if (sem_init(&m_sem, 0, 0) != 0)
        {
            throw std::exception();
        }
    }
    // 初始化信号量
    sem(int num)
    {
        // 用于线程同步,当前信号量拥有的资源数为num
        if (sem_init(&m_sem, 0, num) != 0)
        {
            throw std::exception();
        }
    }
    // 释放资源,线程销毁之后调用这个函数即可
    ~sem()
    {
        sem_destroy(&m_sem);
    }
    // 调用该函数会将sem中的资源数-1。


// 若sem中的资源数>0,线程不会阻塞。


// 若sem中的资源数减为0,资源被耗尽,线程被阻塞。


bool wait() { return sem_wait(&m_sem) == 0; } // 调用该函数会将sem中的资源数+1。


// 若有线程调用wait()被阻塞,这时这些线程会解除阻塞,获取到资源之后继续向下运行。


bool post() { return sem_post(&m_sem) == 0; } private: // 信号量 sem_t m_sem; };


四、条件变量

- 条件变量的主要阻塞线程,不能完全保证线程安全,如果要保证线程安全,需要条件变量和互斥锁一起使用。


#include 
#include 

// 条件变量
class cond
{
public:
    // 初始化条件变量
    cond()
    {
        if (pthread_cond_init(&m_cond, NULL) != 0)
        {
            throw std::exception();
        }
    }
    // 销毁释放资源
    ~cond()
    {
        pthread_cond_destroy(&m_cond);
    }
    // 线程阻塞函数,先把调用该函数的线程放入条件变量的请求队列。


// 如果线程已经对互斥锁上锁,那么会将这把锁打开,这样做是为了避免死锁。


// 在线程解除阻塞时,函数内部会帮助这个线程再次将锁锁上,继续向下访问临界区。


bool wait(pthread_mutex_t *m_mutex) { int ret = 0; // 线程解除阻塞返回0 --> return true ret = pthread_cond_wait(&m_cond, m_mutex); return ret == 0; } // 将线程阻塞一定的时间长度,时间到达之后,线程就解除阻塞。


bool timewait(pthread_mutex_t *m_mutex, struct timespec t) { int ret = 0; ret = pthread_cond_timedwait(&m_cond, m_mutex, &t); return ret == 0; } // 唤醒阻塞在条件变量上的线程,至少有一个被解除阻塞 bool signal() { return pthread_cond_signal(&m_cond) == 0; } // 唤醒阻塞在条件变量上的线程,被阻塞的线程全部解除阻塞 bool broadcast() { return pthread_cond_broadcast(&m_cond) == 0; } private: // 条件变量 pthread_cond_t m_cond; };

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/569813.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)

保存