linux用线程实现银行排队叫号系统,1-6linux系统编程——线程间通信——练习:模拟银行的排队系统...

线程间通信

信息交换:

使用多个线程都可见的内存区域

线程互斥锁:

保障有同一把锁保护的共享资源被多个线程互斥访问

互斥锁:pthread_mutex_t

互斥锁初始化:pthread_mutex_init

互斥锁的获取(加锁)pthread_mutex_lock

互斥锁的释放(解锁)pthread_mutex_unlock

线程信号量:

解决多个线程在使用有限资源时的同步问题

线程信号量:sem_t

信号量的初始化:sem_init

信号量的获取:sem_wait

信号量的释放:sem_post

信号量的销毁:sem_destory

原子性操作:

或全执行,或全不执行。

f4bed7f782da43af81aa5e9ed37804b2.png

逻辑图

](http://upload-images.jianshu.io/upload_images/3821352-0f5492e734fe2fc9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

举个例子:模拟排队系统,单运程多线程

新建一个自定义头文件,存放链表结构体

#ifndef __SQ_QUEUE_H__

#define __SQ_QUEUE_H__

// 定义链式队列中元素的实际类型的别名

// 注意:队列中可以存放任意类型的数据

typedef int datatype_t ;

// 定义链式队列中结点的类型及其别名

typedef struct _queue_node

{

datatype_t data;

struct _queue_node *next;

}queue_node_t;

// 定义存放链式队列队首和队尾指针的结构类型及其别名

typedef struct _link_queue

{

queue_node_t *front;

queue_node_t *rear;

}link_queue_t;

// 创建一个空的链式队列

link_queue_t *create_empty_link_queue(void);

// 判断链式队列是否为空,为空返回1,否则,0

int is_empty_of_link_queue(link_queue_t *queue);

// 求链式队列中元素的个数即队列长度

int length_of_link_queue(link_queue_t *queue);

// 入队操作(即在队尾插入数据结点)

int insert_to_link_queue(link_queue_t *queue,

datatype_t x);

// 出队操作(即在对头删除数据结点)

int delete_from_link_queue(link_queue_t *queue,

datatype_t *px);

// 清空链式队列

void clear_link_queue(link_queue_t *queue);

// 销毁链式队列

void destroy_link_queue(link_queue_t *queue);

// 遍历打印链式队列中的数据

void print_data_info_of_link_queue(link_queue_t *queue);

#endif

对链表的操作:新建链表、尾插、头删、清空数据、判断链表长度、删除链表

#include "link_queue.h"

#include #include // 创建链式队列

link_queue_t *create_empty_link_queue(void)

{

// 为包含队首和队尾指针的结点动态申请空间

link_queue_t *queue = (link_queue_t *)malloc(sizeof(link_queue_t));

// 队首指针和队尾指针均指向头结点

queue->front = queue->rear = (queue_node_t *)malloc(sizeof(queue_node_t));

queue->front->next = NULL;

return queue;

}

// 判断链式队列是否为空,为空返回1,否则0

int is_empty_of_link_queue(link_queue_t *queue)

{

return queue->front == queue->rear;

// return queue->front->next == NULL;

}

// 求链式队列的数据元素个数即队列长度

int length_of_link_queue(link_queue_t *queue)

{

int len = 0;

queue_node_t *p = queue->front;

while(p->next != NULL)

{

len++;

p = p->next;

}

return len;

}

// 入队操作,成功返回0,失败-1

int insert_to_link_queue(link_queue_t *queue,

datatype_t x)

{

// 队列不存在,插入失败返回

if(queue == NULL)

return -1;

// 1.为插入的数据申请结点空间

queue_node_t *p = (queue_node_t *)malloc(sizeof(queue_node_t));

p->data = x;

// 2.插入到队尾指针的后一个位置

p->next = queue->rear->next;

queue->rear->next = p;

// 3.更新队尾指针

queue->rear = queue->rear->next;

return 0;

}

// 出队操作,成功,返回0;失败,-1

int delete_from_link_queue(link_queue_t *queue,

datatype_t *px)

{

// 如果队列不存在或队列为空,出队失败

if(queue == NULL || is_empty_of_link_queue(queue))

return -1;

// 1.定位出队的数据结点的位置

queue_node_t *p = queue->front->next;//头删

// 2.将该结点从链式队列中移除

queue->front->next = p->next;

// 3.如果需要,将待出队元素的值传出

if(px != NULL)

*px = p->data;

// 4.释放结点空间

free(p);

// 注意:如果出队之后,队列为空,重定位尾指针的位置

if(queue->front->next == NULL)

queue->rear = queue->front;

return 0;

}

// 清空链式队列

void clear_link_queue(link_queue_t *queue)

{

queue_node_t *p = NULL;

// 循环的采用头删法删除链式队列的数据结点直到队列为空

while(!is_empty_of_link_queue(queue))

{

p = queue->front->next;

queue->front->next = p->next;

free(p);

}

}

// 销毁链式队列

void destroy_link_queue(link_queue_t *queue)

{

// 清空链式队列

clear_link_queue(queue);

// 释放链式队列头结点空间

free(queue->front);

// 释放队首和队尾指针结点空间

free(queue);

}

// 根据实际datatype_t类型打印数据

static void print_data(datatype_t x)

{

printf("%d ", x);

}

// 遍历打印链式队列的数据结点

void print_data_info_of_link_queue(link_queue_t *queue)

{

queue_node_t *p = queue->front;

printf("linkqueue : ");

while(p->next != NULL)

{

p = p->next;

print_data(p->data);

}

printf("\n");

}

产生链表,随时间间隔插入和删除,有互斥锁

// 练习:模拟银行的排队系统

#include #include "link_queue.h"

#include #include #include #define MAX_CLIENT_COUNT 100

// 全局队列:用于存放用户ID的链式队列

link_queue_t *queue;

// 互斥锁:用于保障生产者线程和消费者线程互斥访问用户队列

pthread_mutex_t mutex;

// 用户数信号量:用于表示当前可用的用户个数

sem_t client_sem;

// 空余排队数信号量:用于表示当前队列中能够继续插入的用户个数

sem_t free_space_sem;

// 生产者线程:用于模拟用户的产生

void *producer_thread(void *arg);

// 消费者线程:用于模拟银行柜台的动作

void *consumer_thread(void *arg);

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

{

pthread_t producer_id;

pthread_t consumer_id;

// 初始化全局用户队列

queue = create_empty_link_queue();

// 初始化互斥锁

pthread_mutex_init(&mutex, NULL);

// 初始化相关信号量

sem_init(&client_sem, 0, 0);

sem_init(&free_space_sem, 0, MAX_CLIENT_COUNT);//限制队列长度

// create threads

pthread_create(&producer_id, NULL, producer_thread, NULL);

pthread_create(&consumer_id, NULL, consumer_thread, NULL);

// join threads

pthread_join(producer_id, NULL);//用户

pthread_join(consumer_id, NULL);//柜台

sem_destroy(&client_sem);

sem_destroy(&free_space_sem);//销毁由sem指向的信号量

return 0;

}

// 生产者线程:用于模拟用户的产生

void *producer_thread(void *arg)

{

int client_no = 0;

while(1)

{

// 1.获取产生用户的资格(即让空余位置-1)

sem_wait(&free_space_sem);

// 2.模拟产生用户ID

client_no = rand()%1000+1;//1~1000

// 3.以互斥的方式向用户队列中插入用户ID信息

pthread_mutex_lock(&mutex);

insert_to_link_queue(queue, client_no);

pthread_mutex_unlock(&mutex);

// 4.模拟打印用户入队信息

printf("client %d is in...queue length : %d\n", client_no, length_of_link_queue(queue));

// 5.可用用户数目+1

sem_post(&client_sem);

// 6.模拟用户的到达时间间隔

sleep(1);

}

}

// 消费者线程:用于模拟银行柜台的动作

void *consumer_thread (void *arg)

{

int client_no = 0;

while (1)

{

// 1.申请可用用户资源(即对可用用户数-1)

sem_wait(&client_sem);

// 2.以互斥的方式从全局用户队列中获取用户ID

pthread_mutex_lock(&mutex);

delete_from_link_queue(queue, &client_no);

pthread_mutex_unlock(&mutex);

// 3.模拟银行柜台的操作

printf("client %d is out...\n", client_no);

// 3.队列空余资源数+1

sem_post(&free_space_sem);

// 4.模拟柜台操作的时间间隔

sleep(rand()%5+1);

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值