apue之多线程实现生产者消费者模型

 

  今天,通过一个停车场的例子巩固下所学的生产者消费者的知识。

  用一个数据结构来描述下停车场结构:

  停车场应该包含停车空间,用数组carpark表示

  停车场的车辆容量capatity

  停车场现有的车辆数目occupied

  下一个进来的车的停车位置nextin

  下一个取走车的停车位置nextout

  记录停车场进入车辆的总和 cars_in

  记录停车场出去车辆的总和cars_out

  互斥锁lock,表示该结构的数据被线程互斥的使用

  条件变量space,表示停车场是否有空位

  条件变量car,描述停车场是否有车

  用户线程同步的线程屏障bar

本项目中有两个生产者(网停车场停车)和两个消费者(从停车场取车)和一个监督者(实时打印停车场消息),用5个线程实现

  main()函数接受接收命令函的参数,初始化ourpark结构数组:

 

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* car_in_handle(void  *carpark_in)

生产者网停车场停车需要读写ourpark数据,由于有2个生产者消费者,所以采用互斥的方式读写,,先获取ourpark的锁:

pthread_mutex_lock(&temp->lock);

释放锁

pthread_mutex_unlock(&temp->lock);

条件变量用来等待一个条件为真,生产者这边需要等待停车场有空位,即等待条件temp->space为真,如果不为真,则需要释放锁,等待消费者的消费,然后重新获取锁

pthread_cond_wait(&temp->space,&temp->lock)

 

消费者取车之后,同样产生信号,告诉生产者

pthread_cond_signal(&temp->car)

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);
}

 

posted on 2017-06-01 11:43  passli  阅读(304)  评论(0编辑  收藏  举报

导航