Linux线程同步

个人主页:Lei宝啊

愿所有美好如期而遇


前言:线程互斥

前面我们谈完了线程互斥,但是有一个问题,所有线程去竞争一个锁,如果有一个线程竞争能力比较强,他一直能够抢到锁,对不同的场景,这也许没问题,只是不合理,但也许就是错的,所以我们需要线程同步,让这些进程能够按照一定的顺序去执行。

条件变量

我们通俗的将,就是在满足我们写的某个条件时,调用一个函数使线程在这个条件变量下等待并释放锁,在线程被唤醒并竞争到锁时,从等待位置再继续执行代码。

定义一个条件变量

仍然是两种方式,同互斥一般,全局静态定义的条件变量,后续不需要destroy,局部定义的需要调用这个函数。

pthread_cond_wait

第一个参数传条件变量,第二个参数传申请到的锁。

这个函数的意思是:使一个线程在cond条件变量下阻塞等待,并释放他所申请的mutex锁,直到线程被唤醒时,线程再去申请锁,如果申请成功,那么再执行这个函数下面的代码。

用法举例:

唤醒线程

broadcast唤醒所有在*cond条件变量下等待的线程,signal唤醒*cond队列首部的线程。

生产消费模型

什么是生产消费模型?就是维护多线程之间的同步和互斥,总结为三种关系,两种角色,以及一个交易场所,交易场所:临时保存数据的内存空间,即某种数据结构。

生产消费模型+条件变量:基于BlockingQueue的生产者消费者模型

在多线程编程中阻塞队列(Blocking Queue)是一种常用于实现生产者和消费者模型的数据结构。其与普通的队列区别在于,当队列为空时,从队列获取元素的操作将会被阻塞,直到队列中被放入了元素;当队列满时,往队列里存放元素的操作也会被阻塞,直到有元素被从队列中取出(以上的操作都是基于不同的线程来说的,线程在对阻塞队列进程操作时会被阻塞)。

cpp 复制代码
#pragma once

#include <pthread.h>
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <unistd.h>
#include "blockqueue.hpp"
using namespace std;

template<typename T>
using func_t = std::function<void(T&)>;
// typedef std::function<void(const T&)> func_t;

#define DataType int
#define TDataBlock BlockQueue<DataType>
#define TYPE Thread<BlockQueue<DataType>>

template<typename T>
class Thread
{
public:
    void Excute()
    {
        _func(_data);
    }
public:
    Thread(func_t<T> func, T &data, const std::string &name="none-name")
        : _func(func), _data(data), _threadname(name), _stop(true)
    {}
    static void *threadroutine(void *args) // 类成员函数,形参是有this指针的!!
    {
        Thread<T> *self = static_cast<Thread<T> *>(args);
        self->Excute();
        return nullptr;
    }
    bool Start()
    {
        int n = pthread_create(&_tid, nullptr, threadroutine, this);
        if(!n)
        {
            _stop = false;
            return true;
        }
        else
        {
            return false;
        }
    }
    void Detach()
    {
        if(!_stop)
        {
            pthread_detach(_tid);
        }
    }
    void Join()
    {
        if(!_stop)
        {
            pthread_join(_tid, nullptr);
        }
    }
    std::string name()
    {
        return _threadname;
    }
    void Stop()
    {
        _stop = true;
    }
    ~Thread() {}

private:
    pthread_t _tid;
    std::string _threadname;
    T &_data;  // 为了让所有的线程访问同一个全局变量
    func_t<T> _func;
    bool _stop;
};
cpp 复制代码
#include "blockqueue.hpp"
#include "Thread_mutex.hpp"

using namespace std;

void funcofmain(TDataBlock& bd)
{

    int cnt1 = 0;
    while(true)
    {
        bd.Push(cnt1);   
        cout << "--funcofmain" << ">>生产in: " << cnt1 << endl;       
        cnt1++;
          
    }
    
}

void funcofless(TDataBlock& bd)
{
    
    int cnt2 = 0;
    while(true)
    {
        bd.Pop(cnt2);  
        cout << "--funcofless" <<  ">>消费out: " << cnt2 << endl;    
        sleep(1);   
    }
    
}

void CommFunc(vector<TYPE>& vtb, int pthreadnum, 
     function<void(TDataBlock&)> func, string what, BlockQueue<DataType>& bq)
{
    for(int i=0; i<pthreadnum; i++)
    {     
        string thread_name = what + "-thread-" + to_string(i+1);
      
        vtb.emplace_back(func, bq);
        vtb.back().Start();                  
    }
}

void MainThread(vector<TYPE>& vtb, int pthreadnum, BlockQueue<DataType>& bq)
{
    CommFunc(vtb, pthreadnum, funcofmain, "main", bq);
}

void LessThread(vector<TYPE>& vtb, int pthreadnum, BlockQueue<DataType>& bq)
{
    CommFunc(vtb, pthreadnum, funcofless, "less", bq);
}

void WaitThread(vector<TYPE>& vtb)
{
    for(auto &e: vtb) e.Join();
}

int main()
{
    int a = 10;

    vector<TYPE> vtb;
    BlockQueue<DataType>* bq = new BlockQueue<DataType>(a);

    MainThread(vtb, 1, *bq);
    LessThread(vtb, 3, *bq);

    WaitThread(vtb);
    

    return 0;
}
cpp 复制代码
#pragma once

#include "Thread_mutex.hpp"
#include <queue>

using namespace std;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t productor = PTHREAD_COND_INITIALIZER;
pthread_cond_t consumer = PTHREAD_COND_INITIALIZER;

template<class T>
class BlockQueue
{
public:

    BlockQueue(){}

    BlockQueue(int data)
        :_data(data)
    {}

    bool IsFull()
    {
        return que.size() == _data;            
    }

    bool IsNull()
    {
        return que.empty();
    }

    void Push(T& in)
    {
        pthread_mutex_lock(&mutex);
        while(IsFull())
        {
            pwait++;
            pthread_cond_wait(&productor, &mutex);
            pwait--;
        }
      
        
        que.push(in);

        if(cwait > 0)
            pthread_cond_signal(&consumer);

        pthread_mutex_unlock(&mutex);
    }

    void Pop(T& out)
    {
        pthread_mutex_lock(&mutex);
        while(IsNull())
        {
            cwait++;
            pthread_cond_wait(&consumer, &mutex);
            cwait--;
        }

   
        out = que.front();
        que.pop();

        if(pwait > 0)
            pthread_cond_signal(&productor);     

        pthread_mutex_unlock(&mutex);  
    }

private:
    int _data;
    queue<T> que;

    int pwait = 0;
    int cwait = 0;
};
相关推荐
小悟空GK4 分钟前
Http介绍
开发语言
阿然成长日记8 分钟前
【Linux】静态库的制作和使用详解
linux·运维·服务器
502胶水20514 分钟前
腾讯地图异步调用
开发语言·ios·swift
SwBack24 分钟前
【pearcmd】通过pearcmd.php 进行GetShell
android·开发语言·php
Lingoesforstudy24 分钟前
c#中的超时终止
开发语言·笔记·c#
**K34 分钟前
C++ 智能指针使用不当导致内存泄漏问题
开发语言·c++·算法
bingbingyihao40 分钟前
Linux安装ftp、Java的FTP上传下载文件工具类
java·linux·centos
u0104058361 小时前
如何利用Java Stream API简化集合操作?
java·开发语言
krb___1 小时前
Gitlab代码管理工具安装配置
linux·服务器·gitlab
湫兮之风1 小时前
C++:.front()函数作用
开发语言·c++