当前位置: 首页 > article >正文

Linux系统编程多线程之条件变量和信号量讲解

一.前言

生产者消费者模型引入

/*

简单的生产者消费者模型
如何查看错误:
        ulimit -a
        发现core file size              (blocks, -c) 0

        生成core文件
        ulimit -c unlimited

        gcc producust.c -o pro -lpthread -g编译后产生段错误

        发现没有生成core文件
        cat /proc/sys/kernel/core_pattern
        如果输出的是一个路径(例如 /var/crash/core.%e.%p),核心文件可能会保存在指定的位置,而不是当前工作目录

        设置核心文件始终生成在当前目录
        sudo sysctl -w kernel.core_pattern=core

        再次运行pro,即生成core文件
*/
/*
    生产者消费者模型(粗略的版本)
*/
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>

struct Node{
    int num;
    struct Node *next;
};

//创建互斥量
pthread_mutex_t mutex;
// 头结点
struct Node * head = NULL;

void * producer(void * arg) {

    // 不断的创建新的节点,添加到链表中
    while(1) {
        pthread_mutex_lock(&mutex);
        struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));
        newNode->next = head;
        head = newNode;
        newNode->num = rand() % 1000;
        printf("add node, num : %d, tid : %ld\n", newNode->num, pthread_self());
        pthread_mutex_unlock(&mutex);
        usleep(100);
    }
    return NULL;
}

void * customer(void * arg) {

    while(1) {
        pthread_mutex_lock(&mutex);
        // 保存头结点的指针
        struct Node * tmp = head;
        if(head!=NULL)
        {
            head = head->next;
            printf("del node, num : %d, tid : %ld\n", tmp->num, pthread_self());
            free(tmp);
            pthread_mutex_unlock(&mutex);
            usleep(100);
        }
        else
        {
            pthread_mutex_unlock(&mutex);
        }
    }
    return  NULL;
}

int main() {

    pthread_mutex_init(&mutex,NULL);
    // 创建5个生产者线程,和5个消费者线程
    pthread_t ptids[5], ctids[5];

    for(int i = 0; i < 5; i++) {
        pthread_create(&ptids[i], NULL, producer, NULL);
        pthread_create(&ctids[i], NULL, customer, NULL);
    }

    for(int i = 0; i < 5; i++) {
        pthread_detach(ptids[i]);
        pthread_detach(ctids[i]);
    }

    while(1)
    {
        sleep(10);
    }
    pthread_mutex_destroy(&mutex);

    pthread_exit(NULL);
    return 0;
}

二.条件变量

 

条件变量不是锁,只是配合我们的互斥锁去使用

条件变量的类型:pthread_cond_t

初始化
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t*restrict attr);

销毁
int pthread_cond_destroy(pthread_cond_t*cond);

一直等待,并且需要通知解除
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t*restrict mutex);

等待多长的时间
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t*restrict mutex,const struct timespec *restrict abstime);

唤醒一个或多个等待
int pthread_cond_signal(pthread_cond_t*cond);

唤醒所有的
int pthread_cond_broadcast(pthread_cond_t*cond);

案例示范

/*
初始化
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t*restrict attr);

销毁
int pthread_cond_destroy(pthread_cond_t*cond);

一直等待,并且需要通知解除
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t*restrict mutex);

等待多长的时间
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t*restrict mutex,const struct timespec *restrict abstime);

唤醒一个或多个等待
int pthread_cond_signal(pthread_cond_t*cond);

唤醒所有的
int pthread_cond_broadcast(pthread_cond_t*cond);
*/

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>

struct Node{
    int num;
    struct Node *next;
};

//创建互斥量
pthread_mutex_t mutex;
//创建条件变量
pthread_cond_t cond;
// 头结点
struct Node * head = NULL;

void * producer(void * arg) {

    // 不断的创建新的节点,添加到链表中
    while(1) {
        pthread_mutex_lock(&mutex);
        struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));
        newNode->next = head;
        head = newNode;
        newNode->num = rand() % 1000;
        printf("add node, num : %d, tid : %ld\n", newNode->num, pthread_self());
        //只要生产一个就通知消费者进行消费
        pthread_cond_signal(&cond);

        pthread_mutex_unlock(&mutex);
        usleep(100);
    }
    return NULL;
}

void * customer(void * arg) {

    while(1) {
        pthread_mutex_lock(&mutex);
        // 保存头结点的指针
        struct Node * tmp = head;
        if(head!=NULL)
        {
            head = head->next;
            printf("del node, num : %d, tid : %ld\n", tmp->num, pthread_self());
            free(tmp);
            pthread_mutex_unlock(&mutex);
            usleep(100);
        }
        else
        {
            //没有数据,阻塞等待
            //当wait这个函数调用阻塞时,会对这个互斥锁进行解锁,当不阻塞时会对这个互斥锁重新加锁
            pthread_cond_wait(&cond,&mutex);
            pthread_mutex_unlock(&mutex);
        }
    }
    return  NULL;
}

int main() {

    pthread_mutex_init(&mutex,NULL);
    pthread_cond_init(&cond,NULL);
    // 创建5个生产者线程,和5个消费者线程
    pthread_t ptids[5], ctids[5];

    for(int i = 0; i < 5; i++) {
        pthread_create(&ptids[i], NULL, producer, NULL);
        pthread_create(&ctids[i], NULL, customer, NULL);
    }

    for(int i = 0; i < 5; i++) {
        pthread_detach(ptids[i]);
        pthread_detach(ctids[i]);
    }

    while(1)
    {
        sleep(10);
    }
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    pthread_exit(NULL);
    return 0;
}

三.信号量

信号量:也是用于阻塞线程的
灯亮可以用,灯灭不可以用,不可以保证多线程数据安全问题,若需要保证,需要跟互斥锁一起使用

信号量的类型 sem_t
int sem_init(sem_t*sem,int pshared, unsigned int value);

int sem_destroy(sem_t*sem);

int sem_wait(sem_t*sem);

int sem_trywait(sem_t*sem);

int sem_timedwait(sem_t*sem,const struct timespec *abs_timeout);

int sem_post(sem_t*sem);

int sem_getvalue(sem_t*sem,int*sval);

 示范代码

/*
初始化
int sem_init(sem_t*sem,int pshared, unsigned int value);
    -参数:
        sem:信号量
        pshared:代表用在线程(0)之间还是进程(其他值)之间
        value:信号量中的值

释放资源
int sem_destroy(sem_t*sem);

等待
int sem_wait(sem_t*sem);
    -没调用一次对信号量值-1,若剩下的值=0阻塞,>0直接返回,调用post+1

int sem_trywait(sem_t*sem);

等待多长时间
int sem_timedwait(sem_t*sem,const struct timespec *abs_timeout);

解锁信号量
int sem_post(sem_t*sem);
    -没调用一次对信号量+1

int sem_getvalue(sem_t*sem,int*sval);
*/
#include <semaphore.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>

struct Node{
    int num;
    struct Node *next;
};

//创建互斥量
pthread_mutex_t mutex;

//创建两个信号量
sem_t psem,csem;

// 头结点
struct Node * head = NULL;

void * producer(void * arg) {

    // 不断的创建新的节点,添加到链表中
    while(1) {

        sem_wait(&psem);

        pthread_mutex_lock(&mutex);
        struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));
        newNode->next = head;
        head = newNode;
        newNode->num = rand() % 1000;
        printf("add node, num : %d, tid : %ld\n", newNode->num, pthread_self());
        pthread_mutex_unlock(&mutex);

        sem_post(&csem);

        usleep(100);
    }
    return NULL;
}

void * customer(void * arg) {

    while(1) {
        sem_wait(&csem);
        pthread_mutex_lock(&mutex);
        // 保存头结点的指针
        struct Node * tmp = head;
        head = head->next;
        printf("del node, num : %d, tid : %ld\n", tmp->num, pthread_self());
        free(tmp);
        pthread_mutex_unlock(&mutex);

        sem_post(&psem);
    }
    return  NULL;
}

int main() {
    
    sem_init(&psem,0,8);
    sem_init(&csem,0,0);

    pthread_mutex_init(&mutex,NULL);
    // 创建5个生产者线程,和5个消费者线程
    pthread_t ptids[5], ctids[5];

    for(int i = 0; i < 5; i++) {
        pthread_create(&ptids[i], NULL, producer, NULL);
        pthread_create(&ctids[i], NULL, customer, NULL);
    }

    for(int i = 0; i < 5; i++) {
        pthread_detach(ptids[i]);
        pthread_detach(ctids[i]);
    }

    while(1)
    {
        sleep(10);
    }
    pthread_mutex_destroy(&mutex);
    pthread_exit(NULL);
    return 0;
}


http://www.kler.cn/a/393878.html

相关文章:

  • PNG图片批量压缩exe工具+功能纯净+不改变原始尺寸
  • 贪心算法day03(最长递增序列问题)
  • 今日 AI 简报 | 开源 RAG 文本分块库、AI代理自动化软件开发框架、多模态统一生成框架、在线图像背景移除等
  • Axure设计之文本编辑器制作教程
  • TortoiseSVN提示服务器凭证检核错误:站点名称不符
  • Linux 函数在多个地方被同时调用时,函数中的变量如何管理,确保互不影响
  • 力扣--树题总结
  • sql文件
  • UniApp 应用、页面与组件的生命周期详解
  • Codeforces Round 984 (Div. 3)
  • 【Ubuntu pip安装mpi4py时报错】
  • 基于单片机的客车载客状况自动检测系统(论文+源码)
  • 从0开始深度学习(29)——文本预处理
  • golang通用后台管理系统08(菜单路由数据vue对接)
  • 科技查新小知识
  • 算法求解 -- (炼码 3854 题)计算满足条件的好二进制字符串数量
  • 基于SSM(Spring + Spring MVC + MyBatis)框架开发的电能计量与客服服务管理系统
  • 蓝队基础1
  • curl 安装最新版
  • 在 Spring Boot 中实时监控 Redis 命令流
  • 基于Java高校排课系统
  • Thread类及常见方法
  • 【Qt】在 Qt Creator 中使用图片资源方法(含素材网站推荐)
  • 实现API接口的自动化
  • PostgreSQL 开启密码验证插件
  • Spring-Webflux + Reactor + Netty 初体验