多线程编程

        找工作的日子渐渐临近了,想来好好复习下之前学的c/c++,不复习还不知道,一复习吓一跳,忘记了太多的东西,没办法,再次学习呗,以前都没有做记录,现在每次复习都来做个笔记,以便以后能够更快的浏览。话不多说,是多线程问题,还是以具体的列子来记录最实在:虽然我很渣渣,希望大家指出不足之处。。。

  问题来源<<多线程生产者消费者模型仿真停车场>>,学软件的都应该学过操作系统原理,与书上面的列题类似,用到知识有:什么是线程,线程的创建,获取线程号,互斥信号量,等。

         问题假设:有一停车场,有两进两出,同时可随时查看车场的车辆数目等;

故根据问问题得出,由于共用的是一个停车场上的资源,故需创建5个级线程,而不是进程。贴出关键部分代码与注释如下:

//《多线程生产者消费者模型仿真停车场》
//实现一个基于生产者消费者模型的的停车场停车信息系统,
//还可以深入理解多线程的创建终止和同步过程,
//以及线程互斥访问共享数据的锁机制原理。

//生产者消费者模型的概念
//互斥量的使用,锁机制的实现方式
//本项目的完整代码如下:
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

#define ONE_SECOND 1000000
#define RANGE 10
#define PERIOD 2
#define NUM_THREADS 4 

// 定义数据结构描述停车场信息
typedef struct {
    int *carpark; // 用一个整数数组 buffer 模拟停车场停车位
    int capacity; // 停车场的车辆容量
    int occupied; // 停车场现有车辆数目
    int nextin;  // 下一个进来的车的停车位置(用 carpark 数组代表的下标表示)
    int nextout; // 下一个取走的车的停车位置(用 carpark 数组代表的下标表示)
    int cars_in; // 记录停车场进入车辆的总和
    int cars_out;  //记录从停车场开出去的车辆总和
    pthread_mutex_t lock; //互斥量,保护该结构中的数据被线程互斥的方式使用
    pthread_cond_t space; //条件变量,描述停车场是否有空位置
    pthread_cond_t car;   //条件变量,描述停车场是否有车
    pthread_barrier_t bar; //线程屏障
} cp_t;

static void * car_in_handler(void *cp_in);
static void * car_out_handler(void *cp_in);
static void * monitor(void *cp_in);
static void initialise(cp_t *cp, int size);

int main(int argc, char *argv[]) {

    if (argc != 2) {
        printf("Usage: %s carparksize\n", argv[0]);
        exit(1);
    }

    cp_t ourpark;

    initialise(&ourpark, atoi(argv[1])); // 初始化停车场数据结构

    pthread_t car_in, car_out, m;  // 定义线程变量
    pthread_t car_in2, car_out2;

    pthread_create(&car_in, NULL, car_in_handler, (void *)&ourpark);  // 创建往停车场停车线程(生产者1)
    pthread_create(&car_out, NULL, car_out_handler, (void *)&ourpark); // 创建从停车场取车线程(消费者1)
    pthread_create(&car_in2, NULL, car_in_handler, (void *)&ourpark); // 创建往停车场停车线程(生产者2)
    pthread_create(&car_out2, NULL, car_out_handler, (void *)&ourpark); // 创建从停车场取车线程(消费者2)
    pthread_create(&m, NULL, monitor, (void *)&ourpark);  // 创建用于监控停车场状况的线程

    // pthread_join 的第二个参数设置为 NULL,表示并不关心线程的返回状态,仅仅等待指定线程(第一个参数)的终止
    pthread_join(car_in, NULL);
    pthread_join(car_out, NULL);
    pthread_join(car_in2, NULL);
    pthread_join(car_out2, NULL);
    pthread_join(m, NULL);

    exit(0);
}

static void initialise(cp_t *cp, int size) {

    cp->occupied = cp->nextin = cp->nextout = cp->cars_in = cp->cars_out = 0;
    cp->capacity = size;  //设置停车场的大小

    cp->carpark = (int *)malloc(cp->capacity * sizeof(*cp->carpark));

    // 初始化线程屏障,NUM_THREADS 表示等待 NUM_THREADS = 4 个线程同步执行 
    pthread_barrier_init(&cp->bar, NULL, NUM_THREADS);


    if (cp->carpark == NULL) {
        perror("malloc()");
        exit(1);
    }

    srand((unsigned int)getpid());

    pthread_mutex_init(&cp->lock, NULL); // 初始化停车场的锁
    pthread_cond_init(&cp->space, NULL); // 初始化描述停车场是否有空位的条件变量
    pthread_cond_init(&cp->car, NULL); // 初始化描述停车场是否有车的条件变量
}

static void* car_in_handler(void *carpark_in) {

    cp_t *temp;
    unsigned int seed;
    temp = (cp_t *)carpark_in;

    // pthread_barrier_wait 函数表明,线程已完成工作,等待其他线程赶来
    pthread_barrier_wait(&temp->bar);
    while (1) {

        // 将线程随机挂起一段时间,模拟车辆到来的的随机性
        usleep(rand_r(&seed) % ONE_SECOND);

        pthread_mutex_lock(&temp->lock);

        // 循环等待直到有停车位
        while (temp->occupied == temp->capacity)
            pthread_cond_wait(&temp->space, &temp->lock);

        // 插入一个辆车(用随机数标识)
        temp->carpark[temp->nextin] = rand_r(&seed) % RANGE;

        // 各变量增量计算
        temp->occupied++;
        temp->nextin++;
        temp->nextin %= temp->capacity; // 循环计数车辆停车位置
        temp->cars_in++;

        // 可能有的人在等有车可取(线程),这是发送 temp->car 条件变量
        pthread_cond_signal(&temp->car);

        // 释放锁
        pthread_mutex_unlock(&temp->lock);

    }
    return ((void *)NULL);

}

static void* car_out_handler(void *carpark_out) {

    cp_t *temp;
    unsigned int seed;
    temp = (cp_t *)carpark_out;
    pthread_barrier_wait(&temp->bar);
    for (; ;) {

        // 将线程随机挂起一段时间,模拟车辆到来的的随机性
        usleep(rand_r(&seed) % ONE_SECOND);

        // 获取保护停车场结构的锁
        pthread_mutex_lock(&temp->lock);

        /* 获得锁后访问 temp->occupied 变量,此时如果车辆数为0(occupied ==0 ),
        pthread_cond_wait 进行的操作是忙等,释放锁(&temp->lock)供其它线程使用。
        直到 &temp->car 条件改变时再次将锁锁住 */
        while (temp->occupied == 0)
            pthread_cond_wait(&temp->car, &temp->lock);

        // 增加相应的增量
        temp->occupied--; // 现有车辆数目减1
        temp->nextout++;
        temp->nextout %= temp->capacity;
        temp->cars_out++;


        // 可能有的人在等有空空车位(线程),这是发送 temp->space 条件变量
        pthread_cond_signal(&temp->space);

        // 释放保护停车场结构的锁
        pthread_mutex_unlock(&temp->lock);

    }
    return ((void *)NULL);

}

// 监控停车场状况
static void *monitor(void *carpark_in) {

    cp_t *temp;
    temp = (cp_t *)carpark_in;

    for (; ;) {
        sleep(PERIOD);

        // 获取锁
        pthread_mutex_lock(&temp->lock);

        /* 证明锁机制保证线程实现的生产者消费者模型正确的方式是:
        temp->cars_in - temp->cars_out - temp->occupied == 0,即总的进来的车 == 
        总的开出去的车 + 停车场现有的车 */
        printf("Delta: %d\n", temp->cars_in - temp->cars_out - temp->occupied);
        printf("Number of cars in carpark: %d\n", temp->occupied);

        // 释放锁
        pthread_mutex_unlock(&temp->lock);

    }

    return ((void *)NULL);
}


       

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值