9.线程同步-互斥量条件变量实现消息队列

199 阅读2分钟
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
#include <signal.h>
#include <vector>
#include <string.h>
using namespace std;

//缓存队列消息的结构体。
struct st_message
{
    int mesgid;     //消息的id
    char message[1024];     //消息内容
}stmesg;

vector<struct st_message> vcache;       //用vector容器做缓存

pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //声明条件变量并初始化
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;    //声明互斥锁并初始化

void incache(int sig);  //生产者,数据入队
void *outcache(void *arg);      //消费者,数据出队线程的主函数

int main()
{
    signal(15, incache);        //接收15的信号,调用生产者函数

    //创建三个消费者线程
    pthread_t thid1=0, thid2=0, thid3=0;
    if(pthread_create(&thid1, NULL, outcache, NULL) != 0) {printf("thid1 faile\n"); exit(-1);}
    if(pthread_create(&thid2, NULL, outcache, NULL) != 0) {printf("thid2 faile\n"); exit(-1);}
    if(pthread_create(&thid3, NULL, outcache, NULL) != 0) {printf("thid3 faile\n"); exit(-1);}

        //等待子线程退出
    printf("join...\n");
    pthread_join(thid1, NULL);
    pthread_join(thid2, NULL);
    pthread_join(thid3, NULL);
    printf("join ok.\n");

    pthread_cond_destroy(&cond);      //主进程退出的时候销毁锁
    pthread_mutex_destroy(&mutex);      //主进程退出的时候销毁锁
    return 0;
}

void incache(int sig)
{
    static int mesgid = 1;      //消息的计数器
    struct st_message stmesg;   //消息内容
    memset(&stmesg, 0, sizeof(struct st_message));

    pthread_mutex_lock(&mutex);     //给缓存队列加锁

    //生产数据,放入缓存队列
    stmesg.mesgid = mesgid++;
    sprintf(stmesg.message, "这是第%d消息", stmesg.mesgid);
    vcache.push_back(stmesg);

    stmesg.mesgid = mesgid++;
    sprintf(stmesg.message, "这是第%d消息", stmesg.mesgid);
    vcache.push_back(stmesg);

    pthread_mutex_unlock(&mutex);       //给缓存队列解锁
    pthread_cond_broadcast(&cond);      //发送条件信号,激活全部的线程
}

void *outcache(void *arg)
{
    struct st_message stmesg;
    while(true)
    {
        pthread_mutex_lock(&mutex);     //给缓存队列加锁

        //如果缓存队列为空,等待,用while防止条件变量虚假唤醒
        /*
            如果缓存中有消息,当前己得到互斥锁,往下操作也是安全。
            如果缓存中没有消息,会pthread_cond_wait,等待条件变量,同时互斥锁解锁,不影响其他进程操作缓存

            当条件信号到了,则pthread_cond_wait返回,此时会持有锁,往下执行也是安全的,但是如果缓存中没有消息
            继续执行取数据,则会出现段错误,应该要在返回时立即判断是否有消息,没有的话继续等待条件变量,同时
            解锁,不影响其他线程操作缓存,所以这里要用while。   
        */
        while(vcache.size() == 0)
        {
            pthread_cond_wait(&cond, &mutex);
        }

        //从缓存队列中获取第一条记录,然后删除该记录
        memcpy(&stmesg, &vcache[0], sizeof(struct st_message));     //内存拷贝
        vcache.erase(vcache.begin());

        pthread_mutex_unlock(&mutex);       //给缓存队列解锁

        //以下是处理业务的代码
        printf("pthid=%ld, mesgid=%d, message=%s\n", pthread_self(), stmesg.mesgid, stmesg.message);
        usleep(100);
    }
}