下面写个多个线程操作共享变量来抢票的售票系统代码:
1.为什么可能无法获得争取结果?
if 语句
判断条件为真以后,代码可以并发的切换到其他线程。usleep
这个模拟漫长业务的过程中,可能有很多个线程会进入该代码段。ticket--
操作本身就不是一个原子操作。
要解决以上问题,需要做到三点:
要做到这三点,本质上就是需要一把锁。Linux上提供的这把锁叫互斥量(mutex)。
初始化互斥量:
销毁互斥量:
销毁互斥量需要注意:
互斥量加锁和解锁:
注意:在特定线程/进程拥有锁的期间,有新的线程来申请锁,pthread_ mutex_lock调用会陷入阻塞(执行流被挂起),等待互斥量解锁。unlock之后对线程进程唤醒操作。此外,加锁的粒度越小越好。
改进上面的抢票系统:
每个线程的寄存器是私有的,在修改数据的时候用的不是拷贝而是xchgb交换,将寄存器的值和内存的值互换。这保证了锁的原子性。因为其他线程申请的话,内存的值为0,申请不到锁。lock:0表示被占, 1表示可以被申请。
- 不保护共享变量的函数
- 函数状态随着被调用,状态发生变化的函数
- 返回指向静态变量指针的函数
- 调用线程不安全函数的函数
死锁是指在一组进程中的各个进程均占有不会释放的资源,但因为互相申请被其他进程所占用而不会释放的资源,而处于的一种永久等待状态。
同步概念:在保证数据安全(一般使用加锁方式
)的情况下,让线程能够按照某种特定的顺序访问临界资源,就叫做同步。
同步实现的事情:当有资源的时候,可以直接获取资源,没有资源的时候,线程进行等待,等待另外的线程生产一个资源,当生产完成的时候,通知等待的线程。
竞态条件:因为时序问题,而导致程序异常,我们称之为竞态条件。在线程场景下,这种问题也不难理解。
条件变量的本质:PCB等待队列+两个接口(等待接口+唤醒接口)
pthread_cond_t 条件变量类型
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
参数:
cond:传入条件变量的地址
attr:条件变量的属性,一般设置为NULL,采用默认属性
int pthread_cond_destroy(pthread_cond_t *cond)
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
参数:
cond:传入条件变量的地址
restrict mutex:传入互斥锁变量的地址
int pthread_cond_signal(pthread_cond_t *cond);
参数:
cond:传入条件变量的地址
//唤醒至少一个PCB等待队列当中的线程
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t lock;
pthread_cond_t cond;
void *task_t2(void *arg)
{
const char *name = (char*)arg;
while(1){
pthread_cond_wait(&cond, &lock);
printf("get cond : %s 活动...\n", name);
}
}
void *task_t1(void *arg)
{
const char *name = (char*)arg;
while(1){
sleep(rand()%3+1);
pthread_cond_signal(&cond);
printf("%s signal done...\n", name);
}
}
int main()
{
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&cond, NULL);
pthread_t t1,t2,t3,t4,t5;
pthread_create(&t1, NULL, task_t1, "thread1");
pthread_create(&t2, NULL, task_t2, "thread2");
pthread_create(&t3, NULL, task_t2, "thread3");
pthread_create(&t4, NULL, task_t2, "thread4");
pthread_create(&t5, NULL, task_t2, "thread5");
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
pthread_join(t4, NULL);
pthread_join(t5, NULL);
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&cond);
return 0;
}
在全局处理文件Global.asax中的Application_Start()方法中加上如下一行代码: protected void Application_Start() { GlobalConfiguration.Configure(WebApiConfig.Register); // 加上下面这一行,异常会返回详细错误信息 GlobalConfiguration.Configuration.Inc...
一直在为安卓和苹果写服务,刚开始的时候全用的Get请求用url传所有的参数,由于url长度的限制大的数据量无法传到服务器,提交图片什么的就更不用说了,后来用的POST请求,记录一下,做了一个很简单的小例子:c#源代码提供大家下载10Solution4.rarios代码IOSHttpPostDemo.rar开始做吧!1建一个空工程Solution4,添加一个类库WcfSer...
1ASCIISTR格式:ASCIISTR(C)说明:将字符串C转换为ASCII字符串,即将C中的ASCII字符保留不变,但非ASCII字符则以ASCII表示返回举例:SQL>SELECT ASCIISTR('AB?CDE数据库') A FROM DUAL;A---------------------AB?CDE\6570\636E\5E932BIN_TO_NUM格式:BIN_TO_NUM(n...
首先最最重要的写在最前面,也是我觉得个人踩得最深的坑,刚接触hadoop的人,缺少的认识:hdfs的理解:它是一个文件系统,跟linux的文件系统是类似的结构,拥有类似的语法,大概就是你在linux上ls查看文件列表,那么hdfs的无非就是hadoop fs -ls。hadoop的输入输出,都是从hdfs读取和写入的,那么比如运行hadoop的word count例子的时候,网上各种大坑教程中
HttpWebRequest wreq = (HttpWebRequest)WebRequest.Create(strUrl); wreq.Timeout = _httpTimeout * 1000; wreq.ReadWriteTimeout = _httpTimeout * 1000; w...
如果有在线修改要素并入库的需求,可以考虑该技术方案,前提是需要用geoserve将postgis数据库的数据发布为wfs服务,然后可以用openlayers 在线进行编辑并实时入库的操作如何删除一个元素
现实的业务场景中,可能需要对Spring的实现类的私有方法进行测试。场景描述:比如XXXService里有 两个函数a、函数b。而实现类XXXServiceImpl中实现了函数a、函数b,还包含私有方法函数c和函数d。要写一个XXXTestController来调用XXXServiceImpl的函数c。面临几个问题:1、如果注入接口,则无法调用实现类的私有类。2、如果注...
Hive中定义变量内置命名空间Hive内置命名空间包含了hivevar、hiveconf、system和env。在Hive中写入hivevar变量hive --define/--hivevar key=value显示变量set env:HOMEset hivevar:keyset key给变量赋值set key=valueset hivevar:key=value在sql语句中调用变量cre...
做即时通信项目时,需要与OA系统对接接口,主要目标是实现在OA里进行一项事项,通过调用我们的接口,即时通知过来,并弹出消息框提示一下。我们的即时通信使用的WCF服务进行通信,在客户端调用通信时,用的就是直接添加服务引用的方式,无可厚非,但是OA系统对接了太多项目,不能使用添加服务引用的方式,问题就来了,不得已只能更改我们的接口。因为不熟悉这一块,浪费了不少时间,总结一下过程,方便以后使用。微软官方...
VSCode下让CSS文件完美支持SCSS或SASS语法方法习惯Webpack + PostCSS后, 通常PostCSS都是直接对CSS文件进行处理, 但是大部分习惯SCSS/SASS/LESS的朋友也许不适应了. 我专门研究了一下, 在Visual Studio Code编辑器下如果配置相关代码和设置达到CSS文件完美编写SCSS的办法, 其他语法类型原理相似, 这里以SCSS为例.开始配置V...
Linux虚拟文件系统剖析:文件打开、读、写逻辑[email protected] Linux文件系统剖析:文件打开操作本文主要通过分析linux系统中的文件打开逻辑,来掌握linux虚拟文件系统相关的数据结构、函数等知识点,将之前的各个点的知识串联成一个整体。系统中给所有文件系统不但依赖VFS,而且...
C++的标准类库被修订了两次,有两个标准 C92和C99,这两个库现在都在并行使用,用 .h 包含的是c92 ,不带 .h 的是c99的头文件,对于普通用户来说这两者没有什么区别,区别是在内部函数的具体实现上。旧的C++头文件是官方明确反对使用的,但旧的C头文件则没有(以保持对C的兼容性)。据说从 Visual C++ .NET 2003 开始,移除了旧的 iostream 库。其实编译器制造