第一版:是不同的线程各卖各的,会导致最终买了300张票
因为 100 放在局部变量,每个线程人手一个

/*
使用多线程来买票的案例
有 3 个窗口,一共是 100 张票
*/
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
void *sellticket(void*arg){int ticket = 100;while (ticket > 0){printf("%ld is selling the %d ticket.\n",pthread_self(),ticket);ticket--;}return NULL;
}
int main(void){//创建3个子线程pthread_t tid1,tid2,tid3;pthread_create(&tid1,NULL,sellticket,NULL);pthread_create(&tid2,NULL,sellticket,NULL);pthread_create(&tid3,NULL,sellticket,NULL);//回收子线程的资源pthread_join(tid1,NULL);pthread_join(tid2,NULL);pthread_join(tid3,NULL);//设置线程分离// pthread_detach(tid1);// pthread_detach(tid2);// pthread_detach(tid3);//退出主线程pthread_exit(NULL);return 0;
}


第二版:即使设置了全局变量,也会出现前一个线程更改了但是后面的线程没有得到更改后的数据的情况。


第三版:让每个线程休眠 3000 ms ,结果之前重复更改某个数据的效果更明显了


第四版:改成 sleep 6000 ms 有惊喜,居然出现了负数!!!

/*
使用多线程来买票的案例
有 3 个窗口,一共是 100 张票
*/
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
int ticket = 100;
void *sellticket(void*arg){while (ticket > 0){usleep(6000);printf("%ld is selling the %d ticket.\n",pthread_self(),ticket);ticket--;}return NULL;
}
int main(void){//创建3个子线程pthread_t tid1,tid2,tid3;pthread_create(&tid1,NULL,sellticket,NULL);pthread_create(&tid2,NULL,sellticket,NULL);pthread_create(&tid3,NULL,sellticket,NULL);//回收子线程的资源pthread_join(tid1,NULL);pthread_join(tid2,NULL);pthread_join(tid3,NULL);//设置线程分离// pthread_detach(tid1);// pthread_detach(tid2);// pthread_detach(tid3);//退出主线程pthread_exit(NULL);return 0;
}


为什么会产生负数呢?
剩下最后一张票的时候,(i = = 1)
线程1、线程2、线程3 一起抢占 CPU,
当线程 1 进来的时候,符合条件(i= = 1 > 0),进入循环,线程 1 被迫休眠;
交给线程 2 ,线程 2 符合条件(i= = 1 > 0),进入循环,线程 2 也被迫休眠;
交给线程 3 ,线程 3 符合条件(i= = 1 > 0),进入循环,线程 3 也被迫休眠;
线程 1 醒来的时候 ,接着循环,–i ,最终 i = = 0;
线程 2 醒来的时候 ,接着循环,–i ,最终 i = = -1;
线程 3 醒来的时候 ,接着循环,–i ,最终 i == -2;
因为醒过来后再次执行就没有判断了

如何解决呢?
1)对 变量 i 进行操作的时候,其他的线程不能对 i 进行操作;
2)线程进行一系列的操作的时候,那些操作必须是原子操作。不能做到一半其他的线程进入了循环

加上互斥量


在进入临界区前加锁,但是这样会有一个问题:
最终的执行结果都是由同一个线程来执行的。
为什么会出现这种情况?
那样写的加锁的逻辑是:加锁进入循环,等到循环完了才会解锁,而循环结束的了票已经卖完了。

最后改成:循环可以随便进,对数据量进行修改的时候要加锁。

/*互斥量的类型 pthread_mutex_tint pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);- 初始化互斥量- mutex 需要初始化的互斥量变量- attr 互斥量相关的属性,传递 NULL 使用默认的属性- restrict : C语言的修饰符,被修饰的指针不能由另外的指针进行操作pthread_mutex_t *restrict mutex = xxx;pthread_mutex_t * mutex1 = mutex;(有了 restrict 的限制,mutex1 不能对 mutex 进行操作)(这个操作符就是限定一个对象所享有的指针的操作权限。)int pthread_mutex_destroy(pthread_mutex_t *mutex);- 释放互斥量的资源int pthread_mutex_lock(pthread_mutex_t *mutex);- 加锁,阻塞的,如果有一个线程加锁,其他的线程只能阻塞等待int pthread_mutex_trylock(pthread_mutex_t *mutex);- 尝试加锁,如果加锁失败,不会阻塞,会直接返回int pthread_mutex_unlock(pthread_mutex_t *mutex);- 解锁
*/
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
int ticket = 1000;//创建一个互斥量
pthread_mutex_t mutex;
// //第一版写法:最终只有一个线程在卖票// void *sellticket(void*arg){//     //加锁
//     pthread_mutex_lock(&mutex);
//     //业务逻辑
//     while (ticket > 0)
//     {//         usleep(6000);
//         printf("%ld is selling the %d ticket.\n",pthread_self(),ticket);
//         ticket--;
//     }
//     //解锁
//     pthread_mutex_unlock(&mutex);
//     return NULL;
// }//第二版写法
void *sellticket(void*arg){// //加锁
//     pthread_mutex_lock(&mutex);
//业务逻辑while (1){//加锁pthread_mutex_lock(&mutex);if(ticket > 0){usleep(6000);printf("%ld is selling the %d ticket.\n",pthread_self(),ticket);ticket--;}else{//这里也需要解锁,否则跳出了循环不会释放锁造成线程无法结束//解锁pthread_mutex_unlock(&mutex);break;}//解锁pthread_mutex_unlock(&mutex);}return NULL;}int main(void){//初始化互斥量pthread_mutex_init(&mutex,NULL);//创建3个子线程pthread_t tid1,tid2,tid3;pthread_create(&tid1,NULL,sellticket,NULL);pthread_create(&tid2,NULL,sellticket,NULL);pthread_create(&tid3,NULL,sellticket,NULL);//回收子线程的资源pthread_join(tid1,NULL);pthread_join(tid2,NULL);pthread_join(tid3,NULL);//退出主线程pthread_exit(NULL);//释放互斥量资源pthread_mutex_destroy(&mutex);return 0;
}

最终的运行结果:能够看到线程的切换

2022-2-1 牛客 C++项目 —— 线程同步相关推荐

  1. 2022-2-1 牛客C++项目 —— 线程属性

    /*int pthread_attr_init(pthread_attr_t *attr);- 初始化线程属性变量int pthread_attr_destroy(pthread_attr_t *at ...

  2. 2022-2-1 牛客C++项目 —— 线程终止cancel

    /* #include <pthread.h> int pthread_cancel(pthread_t thread); 功能:取消线程(让线程终止) (比如说杀毒软件清理内存清理到一半 ...

  3. 2022-2-1 牛客C++项目 —— 线程分离

    /* #include <pthread.h> int pthread_detach(pthread_t thread); 功能:分离一个线程.被分离的线程在终止的时候,会自动释放资源给系 ...

  4. 2022-1-29 牛客C++项目 —— 线程概述与线程创建

    线程和进程区别有哪些?从信息共享,创建代价这两个角度分别来谈论进程和线程缺点和优点. 栈段和text段会分给每个线程一小段 内核数据基本都是共享的 /* 一般的情况下,main函数所在的线程称之为主线 ...

  5. 仿牛客论坛项目(下)

    代码仓库:https://gitee.com/qiuyusy/community 仿牛客论坛项目(上) 仿牛客论坛项目 15.kafka 1.阻塞队列 2.Kafka入门 简介 术语解释 下载 配置 ...

  6. 仿牛客论坛项目(上)

    代码仓库:https://gitee.com/qiuyusy/community 仿牛客论坛项目(下) 仿牛客论坛项目上 1. Spring 在测试类中使用Spring环境 @Primary的作用 @ ...

  7. 仿牛客论坛项目(3)

    仿牛客论坛项目 一.阻塞队列 1.1 测试 二.kafka入门 2.1 kafka下载 2.2 测试 三.Spring整合kafka 3.1 引入依赖 3.2 修改配置文件 3.3 测试 四.发布系统 ...

  8. 仿牛客社区项目笔记-帖子模块(核心)

    仿牛客社区项目笔记-帖子模块(核心) 1. 帖子模块 1.1 过滤敏感词 1.2 发布帖子 1.3 帖子详情 1.4 显示评论 1.5 添加评论 1.6 私信列表 1.7 发送私信 1. 帖子模块 分 ...

  9. 云服务器上部署仿牛客网项目

    云服务器上部署仿牛客网项目 安装JRE 安装Maven 安装MySQL 给mysql导入数据 安装Redis 安装kafka 安装ElasticSearch Wkhtmltopdf 安装tomcat ...

最新文章

  1. 16.PHP_Ajax模拟服务器登录验证
  2. html 入门例子(一)
  3. 禁用win10触摸屏手势_我才发现win10居然有这么多好用的功能
  4. jvm体系结构概述_JVM体系结构:JVM和JVM体系结构概述
  5. 了解ADF生命周期中的ADF绑定
  6. python合并单元格 索引_python笔记:纵向合并表格
  7. 3.1_ 1_ 内存的基础知识
  8. Git配置信息相关命令
  9. python文本筛选html,从html页面的列表元素中筛选数据
  10. 单片机c语言程序设计实训100例基于pic pdf,单片机C语言程序设计实训100例 基于AVR+Proteus仿真.pdf...
  11. rdkit Recap、BRICS分子片段拆分与合成
  12. pm9screw php,PHP使用Screw把源代码加密
  13. AFNetWorking下载视频文件
  14. android mcc 模拟,Android 读取MCC, MNC
  15. 最火的几颗国产视频芯片
  16. 五子棋-单机游戏-微信小游戏项目开发入门
  17. iVMS-4200 Vs区别_【欧国联:德国 VS 瑞士】体育足球赛事专业紅單推荐
  18. css overflow属性及使用方法(场景)
  19. 金属学复习【2】--- 纯金属的结晶
  20. while循环——求100以内偶数和

热门文章

  1. 苹果推出Tap to Pay功能,iPhone将成为收费终端
  2. 水星UD6S网卡Linux驱动,水星UD6S无线usb网卡驱动程序下载-水星网络UD6S网卡驱动1.0 最新版-东坡下载...
  3. PICE(3):CassandraStreaming - gRPC-CQL Service
  4. org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManage
  5. Ant Design Vue :使用日历Calendar,中英文切换
  6. 关于怎么将PDF文件转换成PPT格式的方法
  7. 计算机毕业设计SSM城市道路智能停车管理系统【附源码数据库】
  8. C# 目录路径操作和读取文件详解
  9. 台式计算机屏幕扩展,浅谈修图电脑配置(台式/显示器篇)
  10. ps3本服务器维修中,PS3主机部分错误代码一览