6.王道_线程

在这里插入图片描述

1. 从进程到线程

1.1 用户级线程和内核级线程

  • 内存仍然以进程为单位,cpu以线程为单位
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

2. 线程的创建和终止

  • 注意线程不存在父子关系,main函数启动的是主线程,其他都是子线程
    在这里插入图片描述

2.1 线程函数的错误处理

在这里插入图片描述
在这里插入图片描述

2.2 创建线程

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.3 线程和数据共享

  • 全局变量,堆上变量,栈上变量均可共享
    在这里插入图片描述在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述在这里插入图片描述在这里插入图片描述

  • 保证传递过去的变量不能是销毁的。
    在这里插入图片描述

2.4 线程主动退出

在这里插入图片描述

2.5 获取线程退出状态

  • 查看所有线程
    • ps -elLF
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

3. 线程的取消和资源清理

3.1 线程的取消

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 取消机制可能会导致资源泄漏
    在这里插入图片描述在这里插入图片描述

3.2 线程资源清理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 必须在同一个作用域中成对出现,否则会报编译错误。why
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

4. 线程的同步和互斥

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

4.1 互斥锁的基本使用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 临界区越小越好,避免饥饿。

4.2 使用互斥锁访问共享资源

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.3 互斥锁出错的例子

  • 尽量只使用一把锁。
    在这里插入图片描述

在这里插入图片描述

4.4 死锁

  • 第一种死锁

    • 因为加锁的顺序问题,两个线程想多个资源加锁,必须同时访问这两个资源
  • 第二种死锁

    • 一个线程在持有锁的情况下异常终止了。
    • 在这里插入图片描述
  • 第三种锁

    • 一个线程对同一把锁,锁两次。
  • 解锁

    • 在这里插入图片描述

      • 在这里插入图片描述
      • trylock,自己线程加锁和别人加锁,又加锁,依然会报错。
    • 设置mutex(检错锁和递归锁)的属性来避免第三种死锁类型 。只有自己加锁,再加锁才会报错,别人加锁,我再加锁不会报错。

在这里插入图片描述
在这里插入图片描述

  • 互斥锁的类型

    • 互斥锁又称为阻塞锁,mutexlock,lock之后阻塞。
    • 自旋锁,spinlock,lock之后一直占用cpu循环等待
    • 读写锁
      在这里插入图片描述
  • 作业,A再B之前执行


#include<54func.h>
typedef struct shareRes_s
{
    int flag;
    pthread_mutex_t mutex;
}shareRes_t;

void A()
{
    printf("~~~A before\n");
    sleep(3);
    printf("~~~A After\n");
}
void B()
{
    printf("~~~B before\n");
    sleep(3);
    printf("~~~B After\n");
}

void *thFun(void * arg)
{
    shareRes_t* share = (shareRes_t*)arg;

    while(1)
    {
        // 注意只要访问共享资源就要加锁
        pthread_mutex_lock(&share->mutex);
        if(share->flag == 1)
        {
            pthread_mutex_unlock(&share->mutex);
            break;
        }
        pthread_mutex_unlock(&share->mutex);
    }
    B();
}

int main()
{
    pthread_t tid;
    shareRes_t share;
    share.flag = 0; // 刚开始还没有准备好
    pthread_mutex_init(&share.mutex,NULL);
    pthread_create(&tid,NULL,thFun,&share);


    pthread_mutex_lock(&share.mutex);
    share.flag = 1;
    A();
    pthread_mutex_unlock(&share.mutex);


    pthread_join(tid,NULL);


    return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.5 同步和条件变量

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


#include<54func.h>
typedef struct shareRes_s
{
    int flag;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
}shareRes_t;

void A()
{
    printf("~~~A before\n");
    sleep(3);
    printf("~~~A After\n");
}
void B()
{
    printf("~~~B before\n");
    sleep(3);
    printf("~~~B After\n");
}

void *thFun(void * arg)
{
    shareRes_t* share = (shareRes_t*)arg;
    pthread_mutex_lock(&share->mutex);
    if(share->flag != 1)
    {
        pthread_cond_wait(&share->cond,&share->mutex);
    }

    pthread_mutex_unlock(&share->mutex);
    B();
    pthread_exit(NULL);
}

int main()
{
    pthread_t tid;
    shareRes_t share;
    share.flag = 0; // 刚开始还没有准备好
    pthread_mutex_init(&share.mutex,NULL);
    pthread_cond_init(&share.cond,NULL);
    pthread_create(&tid,NULL,thFun,&share);


    pthread_mutex_lock(&share.mutex);
    share.flag = 1;
    A();
    pthread_mutex_unlock(&share.mutex);
    pthread_cond_signal(&share.cond);

    pthread_join(tid,NULL);


    return 0;
}
  • pthread_cond_wait的实现
    在这里插入图片描述
    在这里插入图片描述

火车站买票

在这里插入图片描述

  • 出现负值
#include<54func.h>

typedef struct shareRes_s
{
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    int ticketsNum;
}shareRes_t;

// h 火车站买票:两个窗口卖票,当票的数量少于5张时,就开始加票

void * sellWin(void * arg)
{
    shareRes_t *share = (shareRes_t*)arg;
    while(1)
    {
        //pthread_mutex_lock(&share->mutex);
        //if(share->ticketsNum > 0 )
        //{
        //    share->ticketsNum--;
        //}
        //pthread_mutex_unlock(&share->mutex);
        pthread_mutex_lock(&share->mutex);
        if(share->ticketsNum <=  0 )
        {
            pthread_cond_wait(&share->cond,&share->mutex);
        }
        pthread_mutex_unlock(&share->mutex);

        pthread_mutex_lock(&share->mutex);
        share->ticketsNum--;
        printf("sell %ld: 卖掉一张,剩余:%d\n",pthread_self(),share->ticketsNum);
        pthread_mutex_unlock(&share->mutex);
        sleep(1);
    }
    pthread_exit(NULL);
}

void * addWin(void * arg)
{

    shareRes_t *share = (shareRes_t*)arg;
    while(1)
    {
        pthread_mutex_lock(&share->mutex);
        if(share->ticketsNum < 5 )
        {
            share->ticketsNum++;
            printf("add %ld: 增加一张,剩余:%d\n",pthread_self(),share->ticketsNum);
        }
        pthread_mutex_unlock(&share->mutex);
        pthread_cond_signal(&share->cond);
        sleep(1);
    }
    pthread_exit(NULL);
}
int main()
{
    shareRes_t share;
    share.ticketsNum = 10; // 刚开始是10张票
    pthread_cond_init(&share.cond,NULL);
    pthread_mutex_init(&share.mutex,NULL);
    pthread_t sell1,sell2,addTick;

    int ret = pthread_create(&sell1,NULL,sellWin,&share);
    THREAD_ERROR_CHECK(ret,"pthread_create sell1");

    ret = pthread_create(&sell2,NULL,sellWin,&share);
    THREAD_ERROR_CHECK(ret,"pthread_create sell2");


    ret = pthread_create(&addTick,NULL,addWin,&share);
    THREAD_ERROR_CHECK(ret,"pthread_create sadd");

    pthread_cond_destroy(&share.cond);
    pthread_mutex_destroy(&share.mutex);
    pthread_join(sell1,NULL);
    pthread_join(sell2,NULL);
    pthread_join(addTick,NULL);
    return 0;
}
  • 现在没问题的
#include<54func.h>

typedef struct shareRes_s
{
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    int ticketsNum;
}shareRes_t;

// h 火车站买票:两个窗口卖票,当票的数量少于5张时,就开始加票

void * sellWin(void * arg)
{
    shareRes_t *share = (shareRes_t*)arg;
    while(1)
    {
        //pthread_mutex_lock(&share->mutex);
        //if(share->ticketsNum > 0 )
        //{
        //    share->ticketsNum--;
        //}
        //pthread_mutex_unlock(&share->mutex);
        pthread_mutex_lock(&share->mutex);
        if(share->ticketsNum <=  0 )
        {
            pthread_cond_wait(&share->cond,&share->mutex);
        }

        // 刚开始我没有这一个;:
        if(share->ticketsNum >  0 )
        {
            share->ticketsNum--;
            printf("sell %ld: 卖掉一张,剩余:%d\n",pthread_self(),share->ticketsNum);
        }
        pthread_mutex_unlock(&share->mutex);
        sleep(1);
    }
    pthread_exit(NULL);
}

void * addWin(void * arg)
{

    shareRes_t *share = (shareRes_t*)arg;
    while(1)
    {
        pthread_mutex_lock(&share->mutex);
        if(share->ticketsNum < 5 )
        {
            share->ticketsNum++;
            printf("add %ld: 增加一张,剩余:%d\n",pthread_self(),share->ticketsNum);
        }
        pthread_mutex_unlock(&share->mutex);
        pthread_cond_signal(&share->cond);
        sleep(1);
    }
    pthread_exit(NULL);
}
int main()
{
    shareRes_t share;
    share.ticketsNum = 10; // 刚开始是10张票
    pthread_cond_init(&share.cond,NULL);
    pthread_mutex_init(&share.mutex,NULL);
    pthread_t sell1,sell2,addTick;

    int ret = pthread_create(&sell1,NULL,sellWin,&share);
    THREAD_ERROR_CHECK(ret,"pthread_create sell1");

    ret = pthread_create(&sell2,NULL,sellWin,&share);
    THREAD_ERROR_CHECK(ret,"pthread_create sell2");


    ret = pthread_create(&addTick,NULL,addWin,&share);
    THREAD_ERROR_CHECK(ret,"pthread_create sadd");

    pthread_cond_destroy(&share.cond);
    pthread_mutex_destroy(&share.mutex);
    pthread_join(sell1,NULL);
    pthread_join(sell2,NULL);
    pthread_join(addTick,NULL);
    return 0;
}

在创建所有线程之后立即销毁了条件变量和互斥量,这是不正确的,因为这些资源在线程运行期间还需要被使用。你应该将pthread_cond_destroy(&share.cond);和pthread_mutex_destroy(&share.mutex);这两行移动到所有线程结束(即调用pthread_join之后)的位置。

  • 存在虚假唤醒
#include<54func.h>

typedef struct shareRes_s
{
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    int ticketsNum;
}shareRes_t;

// h 火车站买票:两个窗口卖票,当票的数量少于5张时,就开始加票

void * sellWin(void * arg)
{
    shareRes_t *share = (shareRes_t*)arg;
    while(1)
    {

        pthread_mutex_lock(&share->mutex);
        if(share->ticketsNum<=0)
        {
            pthread_mutex_unlock(&share->mutex);
            break;
        }
        printf("sell %ld: 卖掉一张,剩余:%d\n",pthread_self(),share->ticketsNum);
        share->ticketsNum--;
        if(share->ticketsNum<=10)
        {
            pthread_cond_signal(&share->cond);
        }
        pthread_mutex_unlock(&share->mutex);
        sleep(1);
    }
    pthread_exit(NULL);
}

void * addWin(void * arg)
{

    shareRes_t *share = (shareRes_t*)arg;
    pthread_mutex_lock(&share->mutex);
    if(share->ticketsNum > 10)
    {
        printf("tickets is enough\n");
        pthread_cond_wait(&share->cond,&share->mutex);
        printf("______________________________\n");
    printf("add %ld: 增加10张,剩余:%d\n",pthread_self(),share->ticketsNum);
    }
    share->ticketsNum+=10;
    printf("add %ld: 增加10张,剩余:%d\n",pthread_self(),share->ticketsNum);
    pthread_mutex_unlock(&share->mutex);
    pthread_exit(NULL);
}
int main()
{
    shareRes_t share;
    share.ticketsNum = 20; // 刚开始是10张票
    pthread_cond_init(&share.cond,NULL);
    pthread_mutex_init(&share.mutex,NULL);
    pthread_t sell1,sell2,addTick;

    int ret = pthread_create(&sell1,NULL,sellWin,&share);
    THREAD_ERROR_CHECK(ret,"pthread_create sell1");

    ret = pthread_create(&sell2,NULL,sellWin,&share);
    THREAD_ERROR_CHECK(ret,"pthread_create sell2");


    ret = pthread_create(&addTick,NULL,addWin,&share);
    THREAD_ERROR_CHECK(ret,"pthread_create sadd");

    pthread_cond_destroy(&share.cond);
    pthread_mutex_destroy(&share.mutex);
    pthread_join(sell1,NULL);
    pthread_join(sell2,NULL);
    pthread_join(addTick,NULL);
    return 0;
}

在这里插入图片描述

  • 虚假唤醒的问题:注意pthread_cond_wait的条件判断使用while进行判断

在这里插入图片描述

#include<54func.h>

typedef struct shareRes_s
{
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    int ticketsNum;
}shareRes_t;

// h 火车站买票:两个窗口卖票,当票的数量少于5张时,就开始加票

void * sellWin(void * arg)
{
    shareRes_t *share = (shareRes_t*)arg;
    while(1)
    {

        pthread_mutex_lock(&share->mutex);
        if(share->ticketsNum<=0)
        {
            pthread_mutex_unlock(&share->mutex);
            break;
        }
        printf("sell %ld: 卖掉一张,剩余:%d\n",pthread_self(),share->ticketsNum);
        share->ticketsNum--;
        if(share->ticketsNum<=10 )
        {
            pthread_cond_signal(&share->cond);
        }
        pthread_mutex_unlock(&share->mutex);
        sleep(1);
    }
    pthread_exit(NULL);
}

void * addWin(void * arg)
{

    shareRes_t *share = (shareRes_t*)arg;
    pthread_mutex_lock(&share->mutex);
    while(share->ticketsNum > 10)  // 注意需要while
    {
        pthread_cond_wait(&share->cond,&share->mutex);
    }
    share->ticketsNum+=10;
    printf("add %ld: 增加10张,剩余:%d\n",pthread_self(),share->ticketsNum);
    pthread_mutex_unlock(&share->mutex);
    pthread_exit(NULL);
}
int main()
{
    shareRes_t share;
    share.ticketsNum = 20; // 刚开始是10张票
    pthread_cond_init(&share.cond,NULL);
    pthread_mutex_init(&share.mutex,NULL);
    pthread_t sell1,sell2,addTick;

    int ret = pthread_create(&sell1,NULL,sellWin,&share);
    THREAD_ERROR_CHECK(ret,"pthread_create sell1");

    ret = pthread_create(&sell2,NULL,sellWin,&share);
    THREAD_ERROR_CHECK(ret,"pthread_create sell2");


    ret = pthread_create(&addTick,NULL,addWin,&share);
    THREAD_ERROR_CHECK(ret,"pthread_create sadd");

    pthread_cond_destroy(&share.cond);
    pthread_mutex_destroy(&share.mutex);
    pthread_join(sell1,NULL);
    pthread_join(sell2,NULL);
    pthread_join(addTick,NULL);
    return 0;
}

在这里插入图片描述
在这里插入图片描述

  • 根治虚假唤醒的问腿 if->while
  • 生产者消费者问题
#include <54func.h>

typedef struct shareRes_S
{
    int flag;  // 0 没有  1 牛肉  2 酸菜
    pthread_mutex_t mutex;
    pthread_cond_t cond;
}shareRes_t;


// 吃牛肉
void * classmates1(void * arg)
{
    shareRes_t *share = (shareRes_t*)arg;
    while(1)
    {
        pthread_mutex_lock(&share->mutex);
        while(share->flag!=1)
        {
            pthread_cond_wait(&share->cond,&share->mutex);
        }
        printf("同学1:我吃牛肉了\n");
        share->flag = 0;
        pthread_mutex_unlock(&share->mutex);
        sleep(1);
    }
    pthread_exit(NULL);
}

void * classmates2(void *arg)
{
    shareRes_t *share = (shareRes_t*)arg;
    while(1)
    {
        pthread_mutex_lock(&share->mutex);
        while(share->flag!=2)
        {
            pthread_cond_wait(&share->cond,&share->mutex);
        }
        printf("同学2:我吃酸菜了\n");
        share->flag = 0;
        pthread_mutex_unlock(&share->mutex);
        sleep(1);
    }
    pthread_exit(NULL);

}

int min = 0;
int max = 10;

// 生成 [min, max] 范围内的随机数
void * product(void *arg)
{

    int range = max - min + 1;
    shareRes_t *share = (shareRes_t*)arg;
    while(1)
    {

        int random_num = rand() % range + min;
        pthread_mutex_lock(&share->mutex);
        if(share->flag == 0 && random_num>5)
        {
            share->flag = 1;
            printf("生产者:生产牛肉\n");
            pthread_cond_broadcast(&share->cond);
        }
        if(share->flag == 0 && random_num<5)
        {
            share->flag =2;
            printf("生产者:生成酸菜\n");
            pthread_cond_broadcast(&share->cond);
        }
        pthread_mutex_unlock(&share->mutex);
        sleep(1);
    }
    pthread_exit(NULL);

}
int main()
{
    pthread_t stu1,stu2;
    pthread_t pro;
    shareRes_t share;
    share.flag = 0;

    pthread_mutex_init(&share.mutex,NULL);
    pthread_cond_init(&share.cond,NULL);

    int ret = pthread_create(&stu1,NULL,classmates1,&share);
    THREAD_ERROR_CHECK(ret,"pthread create stu1");

    ret = pthread_create(&stu2,NULL,classmates2,&share);
    THREAD_ERROR_CHECK(ret,"pthread create stu2");

    ret = pthread_create(&pro,NULL,product,&share);
    THREAD_ERROR_CHECK(ret,"pthread create pro");


    pthread_join(stu1,NULL);
    pthread_join(stu2,NULL);
    pthread_join(pro,NULL);
    pthread_cond_destroy(&share.cond);
    pthread_mutex_destroy(&share.mutex);
    return 0;
}

在这里插入图片描述

  • 自己实现的逻辑
#include <54func.h>

// 链表的结构
typedef struct node_s{
    int data;
    struct node_s *pNest;
}node_t;
//队列的结构:链式队列
typedef struct queue_s{
    node_t * pFront;
    node_t * pRear;
    int queueSize;
}queue_t;

typedef struct shareRes_s{
    queue_t queue;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
}shareRes_t;


// d入队
int enQueue(queue_t *pqueue,int data)
{
    node_t * node = (node_t*)malloc(sizeof(node_t));
    node->data = data;
    node->pNest = NULL;
    if(pqueue->queueSize == 0)
    {
        pqueue->pFront = pqueue->pRear = node;
    }
    else
    {
        pqueue->pRear->pNest = node;
        pqueue->pRear = node;
    }
    pqueue->queueSize++;
}

int deQueue(queue_t *pQueue)
{
    if(pQueue->queueSize == 0)
        return 0;

    int tmp = pQueue->pFront->data;
    node_t* node = pQueue->pFront;
    if(pQueue->queueSize == 1)
    {
        pQueue->pFront = pQueue->pRear = NULL;
    }
    else
    {
        pQueue->pFront = pQueue->pFront->pNest;
    }
    pQueue->queueSize--;
    free(node);
    node->pNest = NULL;
    return tmp;
}
int visitQueue(queue_t *pQueue)
{
    node_t * pCur = pQueue->pFront;
    while(pCur)
    {
        printf("%d ",pCur->data);
        pCur = pCur->pNest;
    }
    printf("\n");
}

// 初始商品为8个,最大商品数量为10个
// 生产者 3个  每3秒产生一个商品
// x消费者 2个  先睡眠 5秒  每个线程再每1秒消耗一个

void * pro_thread(void *arg)
{
    shareRes_t * shareRes = (shareRes_t*)arg;
    while(1)
    {
        pthread_mutex_lock(&shareRes->mutex);

        while(shareRes->queue.queueSize>=10)
        {
            pthread_cond_wait(&shareRes->cond,&shareRes->mutex);
        }

        int data = rand()%1000;
        enQueue(&shareRes->queue,data);
        printf("%ld 生产 %d 剩余:%d \n",pthread_self(),data,shareRes->queue.queueSize);
        pthread_cond_broadcast(&shareRes->cond); // 生产完一个商品就广播
        pthread_mutex_unlock(&shareRes->mutex);
        sleep(3);
    }
}

void * cons_thread(void * arg)
{
    shareRes_t * shareRes = (shareRes_t*)arg;
    sleep(5);
    while(1)
    {
        pthread_mutex_lock(&shareRes->mutex);
        while(shareRes->queue.queueSize<=0)
        {
            pthread_cond_wait(&shareRes->cond,&shareRes->mutex);
        }

        int data = deQueue(&shareRes->queue);
        printf("%ld 消费 %d  剩余:%d\n",pthread_self(),data,shareRes->queue.queueSize);
        pthread_cond_broadcast(&shareRes->cond); // 消费完一个商品就广播
        pthread_mutex_unlock(&shareRes->mutex);
        sleep(1);
    }
}
int main()
{
    shareRes_t shareRes;
    memset(&shareRes.queue,0,sizeof(shareRes.queue));
    pthread_cond_init(&shareRes.cond,NULL);
    pthread_mutex_init(&shareRes.mutex,NULL);
    // 初始商品 8个
    for(int i = 0;i<8;i++)
    {
        int data = rand()%1000;
        enQueue(&shareRes.queue,data);
    }
    visitQueue(&shareRes.queue);
    printf("____________________________________________________________\n");
    pthread_t pro1,pro2,pro3;
    pthread_t cons1,cons2;

    pthread_create(&pro1,NULL,pro_thread,&shareRes);
    pthread_create(&pro2,NULL,pro_thread,&shareRes);
    pthread_create(&pro3,NULL,pro_thread,&shareRes);

    pthread_create(&cons1,NULL,cons_thread,&shareRes);
    pthread_create(&cons2,NULL,cons_thread,&shareRes);

    pthread_join(pro1,NULL);
    pthread_join(pro2,NULL);
    pthread_join(pro3,NULL);
    pthread_join(cons1,NULL);
    pthread_join(cons2,NULL);
    pthread_mutex_destroy(&shareRes.mutex);
    pthread_cond_destroy(&shareRes.cond);


    return 0;
}

在这里插入图片描述

  • 修改之后

#include <54func.h>

// 链表的结构
typedef struct node_s{
    int data;
    struct node_s *pNest;
}node_t;
//队列的结构:链式队列
typedef struct queue_s{
    node_t * pFront;
    node_t * pRear;
    int queueSize;
}queue_t;

typedef struct shareRes_s{
    queue_t queue;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
}shareRes_t;


// d入队
int enQueue(queue_t *pqueue,int data)
{
    node_t * node = (node_t*)malloc(sizeof(node_t));
    node->data = data;
    node->pNest = NULL;
    if(pqueue->queueSize == 0)
    {
        pqueue->pFront = pqueue->pRear = node;
    }
    else
    {
        pqueue->pRear->pNest = node;
        pqueue->pRear = node;
    }
    pqueue->queueSize++;
}

int deQueue(queue_t *pQueue)
{
    if(pQueue->queueSize == 0)
        return 0;

    int tmp = pQueue->pFront->data;
    node_t* node = pQueue->pFront;
    if(pQueue->queueSize == 1)
    {
        pQueue->pFront = pQueue->pRear = NULL;
    }
    else
    {
        pQueue->pFront = pQueue->pFront->pNest;
    }
    pQueue->queueSize--;
    free(node);
    node->pNest = NULL;
    return tmp;
}
int visitQueue(queue_t *pQueue)
{
    node_t * pCur = pQueue->pFront;
    while(pCur)
    {
        printf("%d ",pCur->data);
        pCur = pCur->pNest;
    }
    printf("\n");
}

// 初始商品为8个,最大商品数量为10个
// 生产者 3个  每3秒产生一个商品
// x消费者 2个  先睡眠 5秒  每个线程再每1秒消耗一个

void * pro_thread(void *arg)
{
    shareRes_t * shareRes = (shareRes_t*)arg;
    while(1)
    {
        pthread_mutex_lock(&shareRes->mutex);

        while(shareRes->queue.queueSize>=10)
        {
            pthread_cond_wait(&shareRes->cond,&shareRes->mutex);
        }

        int data = rand()%1000;
        enQueue(&shareRes->queue,data);
        printf("%ld 生产 %d 剩余:%d \n",pthread_self(),data,shareRes->queue.queueSize);
        pthread_cond_broadcast(&shareRes->cond); // 生产完一个商品就广播
        pthread_mutex_unlock(&shareRes->mutex);
        sleep(3);
    }
}

void * cons_thread(void * arg)
{
    shareRes_t * shareRes = (shareRes_t*)arg;
    sleep(5);
    while(1)
    {
        pthread_mutex_lock(&shareRes->mutex);
        while(shareRes->queue.queueSize<=0)
        {
            pthread_cond_wait(&shareRes->cond,&shareRes->mutex);
        }

        int data = deQueue(&shareRes->queue);
        printf("%ld 消费 %d  剩余:%d\n",pthread_self(),data,shareRes->queue.queueSize);
        pthread_cond_broadcast(&shareRes->cond); // 消费完一个商品就广播
        pthread_mutex_unlock(&shareRes->mutex);
        sleep(1);
    }
}
int main()
{
    shareRes_t shareRes;
    memset(&shareRes.queue,0,sizeof(shareRes.queue));
    pthread_cond_init(&shareRes.cond,NULL);
    pthread_mutex_init(&shareRes.mutex,NULL);
    // 初始商品 8个
    for(int i = 0;i<8;i++)
    {
        int data = rand()%1000;
        enQueue(&shareRes.queue,data);
    }
    visitQueue(&shareRes.queue);
    printf("____________________________________________________________\n");
    pthread_t pro1,pro2,pro3;
    pthread_t cons1,cons2;

    pthread_create(&pro1,NULL,pro_thread,&shareRes);
    pthread_create(&pro2,NULL,pro_thread,&shareRes);
    pthread_create(&pro3,NULL,pro_thread,&shareRes);

    pthread_create(&cons1,NULL,cons_thread,&shareRes);
    pthread_create(&cons2,NULL,cons_thread,&shareRes);

    pthread_join(pro1,NULL);
    pthread_join(pro2,NULL);
    pthread_join(pro3,NULL);
    pthread_join(cons1,NULL);
    pthread_join(cons2,NULL);
    pthread_mutex_destroy(&shareRes.mutex);
    pthread_cond_destroy(&shareRes.cond);


    return 0;
}

在这里插入图片描述

5. 线程的属性

在这里插入图片描述

6. 线程安全与可重入性

6.1 线程安全

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 静态局部变量,分配在数据段
  • 一般返回值为指针类型的是线程不安全的。

在这里插入图片描述

  • 先事件就调用signal,后事件:加锁,判断,wait

6.2 可重入性

在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

C++封装线程

面向对象的线程的封装

在这里插入图片描述

  • Thread.h

    • #ifndef __THREAD_H__
      #define __THREAD_H__
      #include<pthread.h>
      class Thread
      {
      public:
          Thread();
          virtual ~Thread();
          void start();
          void join();
      private:
          // 线程入口函数
          static void *threadFunc(void *arg);
         // 要求实现的任务
          virtual void run() = 0;   /// 子类实现这个函数即可
      private:
          pthread_t _thid;
          bool _isRuning;
      };
      #endif
      
  • Thread.cc

    • #include<iostream>
      #include<pthread.h>
      #include "Thread.h"
      Thread::Thread()
          :_thid(0),
          _isRuning(false){}
      
      Thread::~Thread()
      {
          if(_isRuning)
          {
              pthread_detach(_thid);
          }
      }
      
      void Thread::start()
      {
          // threadFunc应设置为静态成员函数,因为成员函数的第一个参数为this,第三个参数需要传入一个函数
          // 由于threadFunc设置为静态成员函数导致在其内部没有this,不能调用run函数 
          int ret = pthread_create(&_thid,nullptr,threadFunc,this);
          if(ret)
          {
              perror("pthread_create");
              return;
          }
          _isRuning = true;
      }
      
      void Thread::join()
      {
          if(_isRuning)
          {
              pthread_join(_thid,nullptr);
              _isRuning = false;
          }
      }
      
      void * Thread::threadFunc(void *arg)
      {
          // 得到this指针
          Thread *pthread_this = static_cast<Thread*>(arg);
          if(pthread_this)
          {
              pthread_this->run(); //实现任务
          }
          pthread_exit(nullptr); //return nullptr;
      }
      
      
  #include <iostream>
  #include<unistd.h>  // sleep.h
  #include<memory>
  #include"Thread.h"
  
  using namespace std;
  
  class MyThread:public Thread
  {
  public:
      void run()override
      {
          while(1)
          {
  
          cout<<"The thread id is running"<<endl;
          sleep(1);
          }
      }
  };
  
  // main就是主线程
  int main()
  {
      //Thread *pthread(new MyThread());
      unique_ptr<Thread> pthread(new MyThread());
      pthread->start();
      pthread->join(); // 让主线程等待子线程的执行
      
      std::cout << "Hello world" << std::endl;
      return 0;
  }
  

子类只需继承Thread类,并且自己覆盖run方法即可。
设计的逻辑:子线程的业务代码写在run方法中,在pthread_create注册线程的入口函数为thfun,然后在thfun中运行子线程的业务代码fun方法。
难点:1, 注册的thfun也要写在类中,但是其第一个参数默认为this,所以设计成static。2. 由于static中不能调用成员函数,所以需要传递在pthread_create通过子线程的入口函数参数传递this。

基于对象的线程封装

在这里插入图片描述

  • Thread.h

    • #ifndef __THREAD_H__
      #define __THREAD_H__
      
      #include<pthread.h>
      #include<functional>
      
      using ThreadCallback = function<void()>;
      
      class Thread
      {
      public:
          Thread(ThreadCallback &&cb);
          ~Thread();
          void start();
          void join();
      private:
          // 线程入口函数
          static void *threadFunc(void *arg);
         // 要求实现的任务
          virtual void run() = 0;
      private:
          pthread_t _thid;
          bool _isRuning;
          // 要去实现的任务
          ThreadCallback _cb;
      };
      
      #endif
      
  • Thread.cc

    • #include<iostream>
      #include<pthread.h>
      
      
      #include "Thread.h"
      
      Thread::Thread(ThreadCallback &&cb)
          :_thid(0),
          _isRuning(false),
          _cb(std::move(cb))
          {}
      
      Thread::~Thread()
      {
          if(_isRuning)
          {
              pthread_detach(_thid);
          }
      }
      
      void Thread::start()
      {
          // threadFunc应设置为静态成员函数,因为成员函数的第一个参数为this,第三个参数需要传入一个函数
          // 由于threadFunc设置为静态成员函数导致在其内部没有this,不能调用run函数 
          int ret = pthread_create(&_thid,nullptr,threadFunc,this);
          if(ret)
          {
              perror("pthread_create");
              return;
          }
          _isRuning = true;
      }
      
      void Thread::join()
      {
          if(_isRuning)
          {
              pthread_join(_thid,nullptr);
              _isRuning = false;
          }
      }
      
      void * Thread::threadFunc(void *arg)
      {
          Thread *pth = static_cast<Thread*>(arg);
          if(pth)
          {
           pth->cb();// 回调函数的形式   
          }
          pthread_exit(nullptr); //return nullptr;
      }
      
      
  • main.cc

    #include <iostream>
    #include<unistd.h>  // sleep.h
    #include<memory>
    #include"Thread.h"
    
    using namespace std;
    
    class MyThread:
    {
    public:
        void process()
        {
            while(1)
            {
                cout<<"The thread id is running"<<endl;
                sleep(1);
            }
        }
    };
    
    // main就是主线程
    int main()
    {
        MyThread myThread;
        Thread th(bind(&MyThread::process,&myThread));
        th.start();
        th.join();
        std::cout << "Hello world" << std::endl;
        return 0;
    }
    

生产者消费者问题

面向对象的封装

  • utexLock.h

    • #ifndef __MUTEXLOCK_H
      #define __MUTEXLOCK_H
      
      #include<pthread.h>
      class MutexLock
      {
      public:
          MutexLock() ;
          ~MutexLock() ;
          void lock();
          void unlock();
          pthread_mutex_t *getMutexLockPtr()
          {
              return &_mutex;
          }
      private:
          pthread_mutex_t _mutex;
      };
      #endif
      
  • MutexLock.cc

    • #include <iostream>
      #include"MutexLock.h"
      
      MutexLock::MutexLock()
      {
          int ret = pthread_mutex_init(&_mutex,nullptr);
          if(ret)
          {
              perror("pthread_mutex_init");
          }
      }
      
      MutexLock::~MutexLock()
      {
          int ret = pthread_mutex_destroy(&_mutex);
          if(ret)
          {
              perror("pthread_mutex_destory");
          }
      }
      
      void MutexLock::lock()
      {
          int ret = pthread_mutex_lock(&_mutex);
          if(ret)
          {
              perror("pthread_mutex_lock");
          }
      }
      
      void MutexLock::unlock()
      {
          int ret = pthread_mutex_unlock(&_mutex);
          if(ret)
          {
              perror("pthread_mutex_unlock");
          }
      }
      
      
  • Condition.h

    • #ifndef __CONDITION_H__
      #define __CONDITION_H__
      
      #include<pthread.h>
      
      class MutexLock;  // 前向声明,直接使用头文件包含可能会出错
      
      class Condition
      {
      public:
          Condition(MutexLock &mutex) ;
          ~Condition() ;
          void wait();
          void notify();
          void notifyAll();
      private:
          pthread_cond_t _cond;
          MutexLock &_mutex;      
      };
      
      #endif
      
      
  • Condition.cc

    • #include"Condition.h"
      #include"MutexLock.h" 
      // 这里就需要包含头文件了,而不能只是前向声明,因为后面需要访问其成员
      
      Condition::Condition(MutexLock &mutex)
          :_mutex(mutex)
      {
          pthread_cond_init(&_cond,nullptr);
      }
      Condition::~Condition() 
      {
          pthread_cond_destroy(&_cond);
      }
      void Condition::wait()
      {
          pthread_cond_wait(&_cond,_mutex.getMutexLockPtr());
      }
      void Condition:: notify()
      {
          pthread_cond_signal(&_cond);
      }
      void Condition::notifyAll()
      {
          pthread_cond_broadcast(&_cond);
      }
      
      
  • TaskQueue.h

    • #ifndef __TASKQUEUE_H__
      #define __TASKQUEUE_H__
      
      #include<queue>
      #include"MutexLock.h"
      #include"Condition.h"
      
      using std::queue;
      class TaskQueue
      {
      public:
          TaskQueue(size_t queSize);
          ~TaskQueue();
          bool empty()const;
          bool full()const;
          void push(const int &value);
          int pop();
      private:
          size_t _queSize;
          queue<int> _que;
          MutexLock _mutex;
          Condition _notEmpty;
          Condition _notFull;
      };
      
      #endif
      
      
  • TaskQueue.cc

    • #include"TaskQueue.h"
      
      TaskQueue::TaskQueue(size_t queSize)
          :_queSize(queSize),
          _que(),
          _mutex(),
          _notFull(_mutex),
          _notEmpty(_mutex)
      {
      
      }
      TaskQueue::~TaskQueue()
      {}
      
      bool TaskQueue::empty()const
      {
          return _que.size() == 0;
      }
      
      bool TaskQueue::full()const
      {
          return _que.size() == _queSize;
      }
      
      void TaskQueue::push(const int &value)
      {
          _mutex.lock();
          if(full())
          {
              _notFull.wait();
          }
          _que.push(value);
          _notEmpty.notify();
          _mutex.unlock();
      }
      
      int  TaskQueue::pop()
      {
      
          _mutex.lock();
      
          if(empty())
          {
              _notEmpty.wait();
          }
      
          int tmp = _que.front();
          _que.pop();
          _notFull.notify();
          _mutex.unlock();
      
          return tmp;
      }
      
      
  • Produces.h

    • #ifndef __PRODUCER_H__
      #define __PRODUCER_H__
      
      #include<stdlib.h>  // 使用随机数i
      #include <unistd.h> //sleer
      #include<iostream>
      #include"Thread.h"
      #include"TaskQueue.h"
      
      class Producer
          : public Thread
      {
      public:
          Producer(TaskQueue &taskQue)
              :_taskQue(taskQue) {}
          ~Producer() {}
      
          void run() override
          {
              int cnt = 20;
              ::srand(clock());
              while(cnt-->0)
              {
                  // 一般为了表明此函数是c中的函数,使用::,你们空间
                  int num = ::rand()%100;
                  _taskQue.push(num);
                  std::cout<<">> produce number = "<<num<<std::endl;
                  sleep(1);
              }
          }
      private:
          TaskQueue & _taskQue;
      };
      
      #endif
      
      
  • Consumers.h

    • #ifndef __CONSUMER_H__
      #define __CONSUMER_H__
      
      #include<stdlib.h>  // 使用随机数i
      #include <unistd.h> //sleer
      #include<iostream>
      #include"Thread.h"
      #include"TaskQueue.h"
      
      class Consumer 
          : public Thread
      {
      public:
          Consumer(TaskQueue &taskQue)
              :_taskQue(taskQue) {}
          ~Consumer() {}
      
          void run() override
          {
              int cnt = 20;
              while(cnt-->0)
              {
                  // 一般为了表明此函数是c中的函数,使用::,你们空间
                  int num = _taskQue.pop();
                  std::cout<<">> consume number = "<<num<<std::endl;
                  sleep(1);
              }
          }
      private:
          TaskQueue & _taskQue;
      };
      
      #endif
      
  • Thread.h

    • #ifndef __THREAD_H__
      #define __THREAD_H__
      
      #include<pthread.h>
      class Thread
      {
      public:
          Thread();
          virtual ~Thread();
          void start();
          void join();
      private:
          // 线程入口函数
          static void *threadFunc(void *arg);
         // 要求实现的任务
          virtual void run() = 0;
      private:
          pthread_t _thid;
          bool _isRuning;
      };
      
      #endif
      
      
  • Thread.cc

    • #include<iostream>
      #include<pthread.h>
      
      
      #include "Thread.h"
      Thread::Thread()
          :_thid(0),
          _isRuning(false){}
      
      Thread::~Thread()
      {
          if(_isRuning)
          {
              pthread_detach(_thid);
          }
      }
      
      void Thread::start()
      {
          // threadFunc应设置为静态成员函数,因为成员函数的第一个参数为this,第三个参数需要传入一个函数
          // 由于threadFunc设置为静态成员函数导致在其内部没有this,不能调用run函数 
          int ret = pthread_create(&_thid,nullptr,threadFunc,this);
          if(ret)
          {
              perror("pthread_create");
              return;
          }
          _isRuning = true;
      }
      
      void Thread::join()
      {
          if(_isRuning)
          {
              pthread_join(_thid,nullptr);
              _isRuning = false;
          }
      }
      
      void * Thread::threadFunc(void *arg)
      {
          // 得到this指针
          Thread *pthread_this = static_cast<Thread*>(arg);
          if(pthread_this)
          {
              pthread_this->run(); //实现任务
          }
          pthread_exit(nullptr); //return nullptr;
      }
      
      
  • Test.cc

    • #include <iostream>
      #include<memory>
      #include"Producer.h"
      #include"Consumer.h"
      
      using std::cout;
      using std::endl;
      using std::unique_ptr;
      
      void test()
      {
          TaskQueue taskQue(10);
          unique_ptr<Thread> produce(new Producer(taskQue));
          unique_ptr<Thread> consume(new Consumer(taskQue));
          
          produce->start();
          consume->start();
      
          produce->join();
          produce->join();
      }
      int main()
      {
          test();
          std::cout << "Hello world" << std::endl;
          return 0;
      }
      
      
  • 问题1

当消费者改为while(1)最后会卡在消费者的pop处
在这里插入图片描述
在这里插入图片描述
由于生产者已经生产完毕,没有会唤醒消费者

  • 使用RAII技术管理互斥锁的解锁和释放
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 虚假唤醒

在这里插入图片描述
在这里插入图片描述

  • MutexLock应该禁止复制

  • MutexLock应该具有对象语义:禁止复制

    • 对象语义:不能进行复制和赋值

    • 值语义:可以进行复制和赋值

    • NoCopyable.h

      • #ifndef __NOCOPYABLE_H__
        #define __NOCOPYABLE_H__
        
        class NoCopyable
        {
        public:
            NoCopyable() {}
            ~NoCopyable() {}
            NoCopyable(const NoCopyable &rhs) = delete ;
            NoCopyable &operator=(const NoCopyable &rhs)=delete ;
        private:
        
        };
        #endif
        
      • 为了让Nocopyable不能创建对象但是可以被继承

        • #ifndef __NOCOPYABLE_H__
          #define __NOCOPYABLE_H__
          
          class NoCopyable
          {
          protected:
              NoCopyable() {}
              ~NoCopyable() {}
              NoCopyable(const NoCopyable &rhs) = delete ;
              NoCopyable &operator=(const NoCopyable &rhs)=delete ;
          private:
          
          };
          #endif
          
    • Example.h

      • #ifndef __EXAMPLE_H__
        #define __EXAMPLE_H__
        #include"NoCopyable.h"
        class Example
        :NoCopyable
        {
        public:
            Example() {}
            ~Example() {}
        
        private:
        
        };
        #endif
        
    • test.c

      • #include <iostream>
        #include "Example.h"
        
        int main()
        {
            Example ex1;
            Example ex2 = ex1; // error
        
            std::cout << "Hello world" << std::endl;
            return 0;
        }
        
        

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值