主线故事:
有4个人玩游戏输了,惩罚:
设计模式:
运行环境:
unix-like系统 或 GNU_C库 或 同等条件 可以在IDE集成环境下也可以编译后在终端单独运行
进程持续1分钟以内
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
#include
#include
pthread_spinlock_t spinlock;
pthread_barrier_t barrier;
// 这是被cancel的时间显示线程的清理函数
void cleanup_func(void *p)
{
printf("%ld pthread_exit\n", pthread_self());
}
// 用于显示时间的线程
void *get_time(void *p)
{
// 注册清理函数
pthread_cleanup_push(cleanup_func, NULL);
// 每隔1秒显示当前时间
while (1)
{
time_t rawtime;
struct tm *info;
char buffer[128];
time(&rawtime);
info = localtime(&rawtime);
strftime(buffer, 128, "%H:%M:%S", info);
printf("%s\n", buffer);
sleep(1);
}
pthread_cleanup_pop(1);
pthread_exit(NULL);
}
// 用于回显余额
void balance_echo()
{
char buf[128] = {0};
// 打开
int fd = open("account_balance", O_RDWR);
// 读
pread(fd, buf, 128, 0);
// 打印在stdout
printf("卡内余额:$%s\n", buf);
// 关闭
close(fd);
}
// 用于处理每台ATM不同的存钱逻辑
void atm_handler(int serial_number)
{
char buf[128] = {0};
int fd = open("account_balance", O_RDWR);
// 储蓄序列号乘以500000的钱
int count = serial_number * 500000;
// 上自旋锁
pthread_spin_lock(&spinlock);
// 读取余额
pread(fd, buf, 128, 0);
// 字符串转整数
long long ab = strtoll(buf, NULL, 10);
for (size_t i = 0; i < count; i++)
{
// 一块一块加,测试自旋锁是不是好使
ab += 1;
// 写入buf,整数转字符串
snprintf(buf, 128, "%lld", ab);
// 写入余额文件
pwrite(fd, buf, strlen(buf), 0);
}
// 解自旋锁
pthread_spin_unlock(&spinlock);
close(fd);
}
void *spinlock_in_barrier(void *p)
{
// void*标准转整 便于使用
int num = *((int *)p);
// 调用ATM储蓄逻辑
atm_handler(num);
// 当某线程到达屏障点时输出
printf("%ld 到达了屏障点\n", pthread_self());
// 等4个储蓄线程全到
pthread_barrier_wait(&barrier);
// 每个线程在自己的ATM显示屏上查询余额,而不是在主线程中
balance_echo();
// 线程结束
printf("%ld pthread_exit\n", pthread_self());
pthread_exit(NULL);
}
void account_balance_init()
{
// 如果该文件存在就删除
if (access("account_balance", F_OK) == 0)
{
remove("account_balance");
}
// 创建文件且有读写权限
int fd = open("account_balance", O_RDWR | O_CREAT, 0700);
// 卡内初始余额就是5块钱
char buf[8] = "5";
write(fd, buf, strlen(buf));
close(fd);
}
// 创建1个计时线程,4个ATM线程并回收他们
void create_join_pthread()
{
pthread_t tids[5] = {0};
int i;
// ATM的序列号,表示不同的ATM,存不同数额的钱
int arr[5] = {0, 2, 4, 6, 8};
pthread_create(&tids[0], NULL, get_time, NULL);
for (i = 1; i < 5; i++)
{
pthread_create(&tids[i], NULL, spinlock_in_barrier, &arr[i]);
}
for (i = 1; i < 5; i++)
{
pthread_join(tids[i], NULL);
printf("%lu join\n", tids[i]);
}
// 当4条ATM线程都返回时,回收计时线程
if (pthread_cancel(tids[0]))
{
perror("cancel");
}
pthread_join(tids[0], NULL);
printf("%lu join\n", tids[0]);
}
int main()
{
// 初始化账户余额文件 ,设为5块钱
account_balance_init();
// 初始化自旋锁
pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE);
// 初始化屏障,设为需要触发4次
pthread_barrier_init(&barrier, NULL, 4);
// 创建及回收5条线程
create_join_pthread();
// 销毁自旋锁
pthread_spin_destroy(&spinlock);
// 销毁屏障
pthread_barrier_destroy(&barrier);
return 0;
}