天道酬勤,学无止境

HttpApplicationState - 如果线程安全,为什么会存在竞争条件?(HttpApplicationState - Why does Race condition exist if it is thread safe?)

问题

我刚刚读了一篇文章,描述了 HttpApplicationState 如何使用AcquireRead() / AcquireWrite()函数来管理并发访问。 它继续解释说,在某些情况下,我们需要在 Application 对象上使用显式的Lock()Unlock()以避免竞争条件。

如果并发访问是由对象隐式处理的,我无法理解为什么应用程序状态应该存在竞争条件。

有人可以向我解释一下吗? 为什么我需要使用Application.Lock()Application.Unlock() ? 谢谢你 !

回答1

AcquireRead 和 AcquireWrite 方法位于内部 HttpApplicationStateLock 类中,因此您不要自己使用它们。 它们同步访问,但仅用于单个读取或写入。 如果您需要同步访问,请从您的代码中使用 Lock 和 Unlock 方法。

如果您正在更改不是单次读取或写入的内容,您通常需要同步访问,例如添加两个相互依赖的应用程序项目,或者首先检查项目是否存在然后添加它:

Application.Lock()
if (Application["info"] == null) {
   Application.Add("info", FetchInfoFromDatabase());
}
Application.Unlock();
回答2

HttpApplicationState - 所有全局访问变量都可见的地方

正在使用该应用程序的用户。 所以为了在改变时避免竞争条件

变量的值。 我们需要一些预防措施,这就是我们使用的原因

Application.Lock() 并在工作完成后将相同的变量释放给其他人

使用 Application.Unlock() 排队

Application.Lock()
Application("VisitorCount") = Convert.ToInt32(Application("VisitorCount")) + 1
Application.UnLock()

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 为什么在C#中,字典比哈希表更受青睐?(Why is Dictionary preferred over Hashtable in C#?)
    问题 在大多数编程语言中,字典比哈希表更受青睐。 背后的原因是什么? 回答1 对于它的价值,字典在概念上是一个哈希表。 如果您的意思是“为什么我们为什么要使用Dictionary<TKey, TValue>类而不是Hashtable类?”,这是一个简单的答案: Dictionary<TKey, TValue>是泛型类型,而Hashtable不是。 这意味着您可以使用Dictionary<TKey, TValue>获得类型安全性,因为您不能在其中插入任何随机对象,也不必强制转换取出的值。 有趣的是,.NET Framework中的Dictionary<TKey, TValue>实现基于Hashtable ,您可以从其源代码中的此注释中看出: 通用字典是从Hashtable的来源复制而来的 资源 回答2 Dictionary <<< >>> Hashtable差异: 通用<<< >>>非通用需要自己的线程同步<<< >>>通过Synchronized()方法提供线程安全版本枚举项: KeyValuePair <<< >>>枚举项: DictionaryEntry 较新(> .NET 2.0 )<<< >>>较旧(自.NET 1.0起) 在System.Collections中。通用<<< >>>在System.Collections中请求不存在的键引发异常<<< >>
  • 《java并发编程实战》总结
    第1章 简介 线程的优势: ①发挥多处理器的强大优势 ②建模的简单性 ③异步事件的简化处理④相应更灵敏的用户界面 线程带来的风险: ①安全性问②活跃性问题③性能问题 第2章 线程安全性 2.1什么是线程安全性 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。 在线程安全的类中封装了必要的同步机制,因此客户端无需进一步采取同步措施。 无状态对象一定是线程安全的。 2.2原子性 2.2.1竞态条件 竞态条件:当某个计算的正确性取决于多个线程的交替执行时序时,那么就会发生竞态条件。换句话说,就是正确的结果要取决于运气。最常见的静态条件类型就是“先检查后执行(Check-Then-Act)”操作,即通过一个可能失效的观测结果来决定下一步的动作。 数据竞争:如果在访问非final类型的域时没有采用同步来进行协调,那么就会出现数据竞争。(JMM知识) 2.3加锁机制 2.3.1内置锁 Java提供了一种内置的锁机制来支持原子性synchronized 2.3.2重入 “重入”意味着获取锁的操作的粒度是“线程”,而不是“调用”。 如下面代码所示:如果没有“重入”,则产生死锁。 public class Widget{ public synchronized
  • Redis 作为唯一的原子 ID 生成器 - Web 应用程序的线程安全方式,以避免竞争条件(Redis as unique atomic id generator - Thread safe way for web app to avoid race condition)
    问题 我计划使用 redis 作为一个独特的原子 ID 生成器。 但是,我担心可能会有来自多个浏览器的模拟 Web 请求。 我想知道,使以下操作原子化的常见做法是什么? get id from redis if id is not found insert id as 0 into redis else store the id in a variable increase id by one store the new id back to redis 如果我在桌面应用程序或移动应用程序中,我会在 Java 中使用synchronized关键字来避免竞争条件。 但是,对于 PHP Web 应用程序呢? 回答1 假设您要生成顺序 ID,您可以使用 Redis 和 INCR 命令而不必担心竞争条件。 由于Redis(大部分)是单线程的,您可以放心,每个请求都会从中获得自己的唯一ID。 此外,您不需要检查 id 键的存在/初始化它,因为 Redis 会为您做这件事(即,如果您 INCR 一个不存在的键,它将首先创建并自动设置为 0)。
  • 单线程程序中可以有竞争条件吗?(Can we have race conditions in a single-thread program?)
    问题 您可以在这里找到关于什么是竞赛条件的很好的解释。 最近,我看到许多人对竞争条件和线程发表了令人困惑的声明。 我了解到,竞争条件只能在线程之间发生。 但是我看到了在事件和基于异步的语言中看起来像竞争条件的代码,即使该程序是单线程的,例如在Node.js,GTK +等中也是如此。 我们可以在单线程程序中有一个竞争条件吗? 回答1 所有示例均使用非常接近Javascript的虚构语言编写。 短的: 争用条件只能发生在两个或多个线程/外部状态之间(其中一个可以是OS)。 我们不能在非I / O执行程序的单线程进程中具有竞争条件。 但是在许多情况下,单线程程序可以: 给出与竞赛条件类似的情况,例如在带有事件循环的基于事件的程序中,但不是真实的竞赛条件例如,或由于程序某些部分的执行取决于外部状态,而触发在其他线程之间或与其他线程之间的竞争条件: 其他程序,例如客户端库线程或服务器系统时钟 I)竞争条件只能在两个或多个线程之间发生 仅当两个或多个线程尝试访问共享资源而又不知道其他线程的未知指令同时修改了共享资源时,才会发生竞争状态。 这给出了不确定的结果。 (这真的很重要。) 即使不容易在代码中读取指令的执行顺序,单线程处理也不过是一系列已知指令的结果,因此可以得出确定的结果。 II)但是我们并不安全 II.1)类似于比赛条件的情况 许多编程语言通过事件或信号实现异步编程功能
  • 竞争条件“check-then-act”和“read-modify-write”(Race conditions “check-then-act” and “read-modify-write”)
    问题 任何人都可以向我解释什么是竞争条件,如何避免它,以及如何在 Java 代码中找到它? 好吧,我几天才知道“竞争条件”,我有两个例子,也许它们不够好,这就是为什么我需要你的帮助:)希望你们中的任何人都可以为我解释。 示例1:检查然后采取行动: if(vector.contains(e))//check { vector.remove(e) } 如果有2个线程可以访问,线程1在检查向量包含e后挂起,e在向量中,然后线程2访问检查然后从向量中删除e,然后线程1回来做删除动作,会发生错误,因为e是已被 thread2 删除。 示例2:读取修改写入: 假设我们在一个方法中有一个计数器变量,一旦方法被调用,计数器增加1, counter++ 这不是原子操作,它有 3 个步骤: 1. 获取值 2. 增加值 3. 分配给值 我对比赛条件的了解都在这里,希望您能与我分享您的知识:) 谢谢 回答1 什么是竞态条件? 检查这个堆栈溢出问题。 竞争条件主要有两种情况:读-修改-写和检查-然后-行动。 对于读取-修改-写入,经典示例是counter++ ,它不是原子操作,因此会导致竞争条件。 对于先检查后行动,有多个示例。 一个例子是当你在 ConcurrentHashMap 中检查键是否存在,然后在 if-case 中做一些工作。 另一个例子是单例类代码: public Singleton
  • Java中的锁
    在学习或者使用Java的过程中进程会遇到各种各样的锁的概念:公平锁、非公平锁、自旋锁、可重入锁、偏向锁、轻量级锁、重量级锁、读写锁、互斥锁等待。这里整理了Java中的各种锁,若有不足之处希望大家在下方留言探讨。 WARNING:本文适合有一定JAVA基础的同学阅读。公平锁和非公平锁 公平锁是指多个线程在等待同一个锁时,必须按照申请锁的先后顺序来一次获得锁。 公平锁的好处是等待锁的线程不会饿死,但是整体效率相对低一些;非公平锁的好处是整体效率相对高一些,但是有些线程可能会饿死或者说很早就在等待锁,但要等很久才会获得锁。其中的原因是公平锁是严格按照请求所的顺序来排队获得锁的,而非公平锁时可以抢占的,即如果在某个时刻有线程需要获取锁,而这个时候刚好锁可用,那么这个线程会直接抢占,而这时阻塞在等待队列的线程则不会被唤醒。 公平锁可以使用new ReentrantLock(true)实现。自旋锁 Java的线程是映射到操作系统的原生线程之上的,如果要阻塞或唤醒一个线程,都需要操作系统来帮忙完成,这就需要从用户态转换到核心态中,因此状态装换需要耗费很多的处理器时间,对于代码简单的同步块(如被synchronized修饰的getter()和setter()方法),状态转换消耗的时间有可能比用户代码执行的时间还要长。 虚拟机的开发团队注意到在许多应用上,共享数据的锁定状态只会持续很短的一段时间
  • 我怎么知道这个 C# 方法是否是线程安全的?(How do I know if this C# method is thread safe?)
    问题 我正在为 ASP.NET 缓存项删除事件创建回调函数。 文档说我应该在一个对象上调用一个方法或者调用我知道将存在(将在范围内),例如静态方法,但它说我需要确保静态是线程安全的。 第 1 部分:我可以做哪些事情来使其非线程安全? 第 2 部分:这是否意味着如果我有 static int addOne(int someNumber){ int foo = someNumber; return foo +1; } 我打电话给 Class.addOne(5); 和 Class.addOne(6); 同时,根据哪个调用首先设置 foo,我是否会得到 6 或 7 的返回值? (即竞争条件) 回答1 addOne函数确实是线程安全的,因为它不访问任何可以被另一个线程访问的数据。 局部变量不能在线程之间共享,因为每个线程都有自己的堆栈。 但是,您必须确保函数参数是值类型而不是引用类型。 static void MyFunction(int x) { ... } // thread safe. The int is copied onto the local stack. static void MyFunction(Object o) { ... } // Not thread safe. Since o is a reference type, it might be shared
  • 带有局部静态变量的 ID 生成器 - 线程安全?(ID generator with local static variable - thread-safe?)
    问题 以下代码在多线程场景中是否会按预期工作? int getUniqueID() { static int ID=0; return ++ID; } ID 没有必要是连续的 - 即使它跳过一个值,也没关系。 能不能说这个函数返回时,返回的值在所有线程中都是唯一的? 回答1 不,不会。 您的处理器将需要执行以下步骤来执行此代码: 从内存中取出 ID 的值到寄存器增加寄存器中的值将增加的值存储到内存中 如果在此(非原子)序列期间发生线程切换,则可能发生以下情况: 线程 a 将值 1 取到寄存器中线程 a 递增该值,因此寄存器现在包含 2 上下文切换线程 b 获取值 1(仍在内存中) 上下文切换线程 a 将 2 存储到内存并返回上下文切换线程 b 将它存储在其寄存器中的值增加到 2 线程 b(也)将值 2 存储到内存并返回 2 因此,两个线程都返回 2。 回答2 不,仍然存在竞争的可能性,因为增量不一定是原子的。 如果您使用原子操作来增加 ID,这应该可以工作。 回答3 如果您只需要一些跨 N 个线程单调递增(或非常接近)的数字,请考虑这个(k 是某个数字,使得 2^k > N): int getUniqueIDBase() { static int ID=0; return ++ID; } int getUniqueID() { return getUniqueIDBase() <<
  • C# 中的空合并运算符 (??) 是线程安全的吗?(Is the null coalescing operator (??) in C# thread-safe?)
    问题 以下代码中是否存在可能导致NullReferenceException的竞争条件? - 或者 - 在空合并运算符检查空值之后但在调用函数之前,是否可以将Callback变量设置为空? class MyClass { public Action Callback { get; set; } public void DoCallback() { (Callback ?? new Action(() => { }))(); } } 编辑 这是一个出于好奇而提出的问题。 我通常不会这样编码。 我不担心Callback变量变得陈旧。 我担心的Exception从抛出存在DoCallback 。 编辑#2 这是我的课: class MyClass { Action Callback { get; set; } public void DoCallbackCoalesce() { (Callback ?? new Action(() => { }))(); } public void DoCallbackIfElse() { if (null != Callback) Callback(); else new Action(() => { })(); } } DoCallbackIfElse方法有一个可能抛出NullReferenceException的竞争条件。
  • Java面试之单例模式浅谈
    单例模式是Java面试中常会问到的一个问题,众所周知,单例模式分为两大部分:饿汉模式和懒汉模式。但是,如果当面试官问道关于单例模式的话,如果你只答出这两种模式,且懒汉模式还是最基础最简陋版的话,那么你可能就要悲剧了。 当被问到单例模式的时候我们到底需要知道哪些知识点呢?接下来我根据我所掌握的知识点进行一些总结,希望对大家能够有所帮助。 一、饿汉模式: 其实从名字就可以辨认出,该模式的写法是在定义私有全局变量时直接初始化变量,饿汉么,既然已经饿了,那就不管什么赶紧吃了,附代码如下: private static Singleton singleton = new Singleton(); public static Singleton backSingletonAction() { return singleton; } 该模式最大的问题是,私有全局变量singleton的创建时机问题,由于被static修饰,当class被加载的时候,singleton就会被创建出来,那么就有可能造成空间浪费,一个单例类就会存在一个对象,那么如果有100个单例类就回有100个对象,但是有可能只用到1个,这种情况下就会有99个对象的空间被浪费,这就是饿汉模式最大的问题。 二、懒汉模式: 顾名思义,这种模式的单例比较懒,只有在用到的时候对象才会被创建出来,可以很大程度的节约空间。懒汉模式的实现由很多种
  • Singleton和HttpApplicationState(Singleton and HttpApplicationState)
    问题 在Web应用程序中,我仅需要一个名为ProcessManager的类的实例。 一种方法是使其成为单例。 另一种方法是使用HttpApplicationState确保我始终访问同一实例,如下所示: public static ProcessManager ProcessManager { get { HttpApplicationState applicationState = HttpContext.Current.Application; if (applicationState["ProcessManager"] == null) { applicationState["ProcessManager"] = new ProcessManager(); } return (ProcessManager)applicationState["ProcessManager"]; } } 哪种方法更好,为什么? 回答1 根据您所提供的有限描述,我将选择一个Singleton,因为它不依赖于HttpContext.Current,并且可以在ASP.Net管道之外使用(例如,当您要编写时单元测试。) (顺便说一句,当您在ApplicationState中设置某些内容时,还需要先在其上调用Lock(),然后在对其进行写操作之后再对其进行Unlock(),以确保它是线程安全的。) 或者
  • 什么是线程安全?一文带你深入理解
    前言欢迎来到操作系统系列,采用图解 + 大白话的形式来讲解,让小白也能看懂,帮助大家快速科普入门。上篇文章有介绍过进程与线程的基础知识,进程下拥有多个线程,虽然多线程间通信十分方便(同进程),但是却带来了线程安全问题,本篇主要就是介绍操作系统中是用什么方法解决多线程安全,废话不多说,进入正文吧。博主希望读者阅读文章后可以养成思考与总结的习惯,只有这样才能把知识消化成自己的东西,而不是单纯的去记忆内容大纲小故事带薪蹲坑,相信都是大伙都爱做的事情,阿星也不例外,但是我司所在的楼层的坑位较少,粥少僧多,十分烦恼。阿星(线程A)每次去厕所(共享资源),门都是锁着的,说明有同事在里面占着坑(线程B持有锁),只能无奈的在外面乖乖的等着,不久后冲水声响起,同事爽完出来(线程B释放锁),阿星一个健步进入厕所把门锁住(线程A持有锁),享受属于自己的空间,晚来的其他同事只能乖乖排队,一切都是那么井然有序。假设门锁坏了,井然有序就不存在了,上厕所不再是享受,而是高度紧张,防止门突然被打开,更糟糕的是,开门时,是个妹子,这下不仅仅是线程安全问题,还有数组越界了。故事说完,扯了那么多,就是想说明,在多线程环境里,对共享资源进行操作,如果多线程之间不做合理的协作(互斥与同步),那么一定会发生翻车现场。竞争条件因为多线程共享进程资源,在操作系统调度进程内的多线程时,必然会出现多线程竞争共享资源问题
  • 根据 CERT 编码规则 POS49-C,访问共享结构中的相邻成员时出现竞争条件?(Race condition when accessing adjacent members in a shared struct, according to CERT coding rule POS49-C?)
    问题 根据 CERT 编码规则 POS49-C,不同线程访问同一结构的不同字段可能会发生冲突。 我使用常规的无符号整数而不是位域。 struct multi_threaded_flags { unsigned int flag1; unsigned int flag2; }; struct multi_threaded_flags flags; void thread1(void) { flags.flag1 = 1; } void thread2(void) { flags.flag2 = 2; } 我可以看到即使是无符号整数,如果编译器决定使用加载/存储 8 个字节而不是 4 个字节,仍然可能存在竞争条件。 我认为编译器永远不会那样做,赛车条件永远不会在这里发生,但这完全只是我的猜测。 是否有任何关于这种情况的明确定义的程序集/编译器文档? 我希望锁定,这是昂贵的,是当这种情况碰巧未定义时的最后手段。 仅供参考,我使用gcc。 回答1 C11内存模型保证对不同结构成员(不是位域的一部分)的访问是独立的,因此在修改来自不同线程的两个标志(即“加载 8 个字节,修改 4,不允许写回 8" 的场景)。 这种保证一般不会扩展到位域,所以你必须小心。 当然,如果您同时从多个线程修改同一个标志,您可能会触发禁止数据竞争,所以不要这样做。 回答2 在 C11 之前,ISO C
  • 为什么总是在循环内调用wait()(Why should wait() always be called inside a loop)
    问题 我读过,我们应该始终从循环中调用wait() : while (!condition) { obj.wait(); } 它可以正常工作而没有循环,那为什么呢? 回答1 您不仅需要循环它,还需要在循环中检查条件。 Java不能保证仅通过notify()/ notifyAll()调用或正确的notify()/ notifyAll()调用来唤醒您的线程。 由于此属性,无环版本可能在您的开发环境上工作,而在生产环境上意外失败。 例如,您正在等待一些东西: synchronized (theObjectYouAreWaitingOn) { while (!carryOn) { theObjectYouAreWaitingOn.wait(); } } 邪恶的线程出现了: theObjectYouAreWaitingOn.notifyAll(); 如果恶意线程没有/不能弄乱carryOn携带的carryOn您只需要继续等待适当的客户即可。 编辑:添加了更多示例。 等待可以中断。 它会抛出InterruptedException,您可能需要将等待结果包装在try-catch中。 根据您的业务需求,您可以退出或取消该异常并继续等待。 回答2 在Object.wait(long milis)的文档中得到了答复 线程也可以唤醒,而不会被通知,中断或超时,即所谓的虚假唤醒。
  • 多线程
    创建线程有哪几种方式?* ①. 继承Thread类创建线程类 定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。 创建Thread子类的实例,即创建了线程对象。 调用线程对象的start()方法来启动该线程。 ②. 通过Runnable接口创建线程类 定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。 创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。 调用线程对象的start()方法来启动该线程。 ③. 通过Callable和Future创建线程 创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask 说一下 runnable 和 callable 有什么区别?* 有点深的问题了,也看出一个Java程序员学习知识的广度。 Runnable接口中的run()方法的返回值是void,它做的事情只是纯粹地去执行run()方法中的代码而已; Callable接口中的call()方法是有返回值的
  • JavaScript 中的数据竞争?(Data Races in JavaScript?)
    问题 让我们假设我运行这段代码。 var score = 0; for (var i = 0; i < arbitrary_length; i++) { async_task(i, function() { score++; }); // increment callback function } 从理论上讲,我知道这会导致数据竞争,并且两个线程试图同时增加可能会导致单个增加,但是,nodejs(和 javascript)已知是单线程的。 我能保证分数的最终值将等于任意长度吗? 回答1 Node 使用事件循环。 您可以将其视为队列。 所以我们可以假设,你的 for 循环放置了function() { score++; } function() { score++; }回调arbitrary_length在此排队时间。 之后js引擎将这些一一运行,每次都增加score 。 所以是的。 如果没有调用回调或从其他地方访问score变量,这是唯一的例外。 实际上,您可以使用此模式并行执行任务,收集结果并在每个任务完成时调用单个回调。 var results = []; for (var i = 0; i < arbitrary_length; i++) { async_task(i, function(result) { results.push(result); if (results
  • 为什么在临界区中需要通知?(Why is notify required inside a critical section?)
    问题 我在这里阅读这本书(官方链接,它是免费的)以了解线程和并行编程。 这是问题。 为什么书中说pthread_cond_signal必须持有锁来防止数据竞争? 我不确定,所以我提到了这个问题(以及这个问题),它基本上是说“不,这不是必需的”。 为什么会出现竞态条件? 描述的竞态条件是什么?在哪里? 有问题的代码和段落如下。 ... 唤醒将在其他线程中运行的线程的代码如下所示: pthread_mutex_lock(&lock); ready = 1; pthread_cond_signal(&cond); pthread_mutex_unlock(&lock); 关于此代码序列的一些注意事项。 首先,在发出信号时(以及在修改全局变量准备好时),我们始终确保持有锁。 这确保我们不会意外地在我们的代码中引入竞争条件。 ... (请参阅免费的官方 pdf 以获取上下文。) 我无法在链接 2 中对一个小问题发表评论,所以这是一个完整的问题。 编辑 1:我知道锁是为了控制对ready变量的访问。 我想知道为什么会有与信号相关的竞争条件。 具体来说, 首先,在发送信号 [...] 时,我们始终确保持有锁。 这确保我们不会意外地在我们的代码中引入竞争条件 编辑 2:我已经看到了资源和评论(来自下面评论的链接和我自己的研究期间),有时在同一页面内说或者(会很好)如果这也可以触及
  • SetEvent ResetEvent WaitForMultipleObjectsEx - 竞争条件?(SetEvent ResetEvent WaitForMultipleObjectsEx - Race condition?)
    问题 我无法理解PulseEvent或竞争条件。 但是为了避免它,我尝试使用SetEvent代替,并且每次在WaitForMultipleObjectsEx之前使用ResetEvent 。 这是我的流程: 线程一 - 使用CreateEvent创建一个自动重置事件,然后我生成并告诉线程二。 线程一 - 告诉线程二运行。 线程二将在事件上执行ResetEvent ,然后立即在事件上启动WaitForMultipleObjectsEx和其他一些用于文件监视的东西。 如果WaitForMultipleObjectsEx返回,并且不是由于事件,则立即重新启动循环。 如果WaitForMultipleObjectsEx返回,由于事件将发出信号,则不要重新启动循环。 所以现在请想象一下这种情况: 线程二 - 循环正在运行线程一 - 需要添加路径,因此它执行(1) SetEvent ,然后(2)向线程 2 发送另一条消息以添加路径,然后(3)向线程 2 发送消息以重新启动循环。 添加路径和重新启动循环的消息不会进入线程二,除非我在两中停止循环,这是由SetEvent完成的。 线程 2 将看到它因事件而停止,因此它不会重新启动循环。 所以它现在会收到添加路径的消息,所以它会添加路径,然后重新启动循环。 线程一 - 需要停止线程,因此它执行 (1) SetEvent然后 (2) 等待消息线程 2
  • mysql 插入竞争条件(mysql insert race condition)
    问题 你如何停止 MySQL 中的竞争条件? 手头的问题是由一个简单的算法引起的: 从表中选择一行如果它不存在,插入它 然后要么你得到一个重复的行,要么你通过唯一/主键阻止它,一个错误。 现在通常我认为交易在这里有帮助,但因为该行不存在,交易实际上并没有帮助(或者我错过了什么?)。 LOCK TABLE 听起来有点矫枉过正,尤其是当表每秒更新多次时。 我能想到的唯一其他解决方案是针对每个不同的 id 使用 GET_LOCK(),但没有更好的方法吗? 这里也没有可扩展性问题吗? 而且,对每个表都这样做听起来有点不自然,因为对我来说这听起来像是高并发数据库中的一个非常普遍的问题。 回答1 你想要的是锁表 或者,如果这看起来有点过分,如何 INSERT IGNORE 并检查该行是否已实际插入。 如果使用 IGNORE 关键字,则在执行 INSERT 语句时发生的错误将被视为警告。 回答2 在我看来,您的 id 列上应该有一个唯一索引,因此重复插入会触发错误,而不是再次被盲目接受。 这可以通过将 id 定义为主键或单独使用唯一索引来完成。 我认为你需要问的第一个问题是为什么你有很多线程做完全相同的工作? 为什么他们必须插入完全相同的行? 在得到回答之后,我认为仅忽略错误将是最高效的解决方案,但衡量这两种方法(GET_LOCK v/s 忽略错误)并亲自查看。 我知道没有其他方法。
  • 术语“线程安全”的含义是什么?(What is the meaning of the term “thread-safe”?)
    问题 这是否意味着两个线程不能同时更改基础数据? 还是这意味着当多个线程执行该代码段时,给定的代码段将以可预测的结果运行? 回答1 线程安全代码是即使许多线程同时执行也可以运行的代码。 http://mindprod.com/jgloss/threadsafe.html 回答2 一个更具信息量的问题是什么使代码不具有线程安全性,并且答案是必须满足四个条件...想象以下代码(它是机器语言翻译) totalRequests = totalRequests + 1 MOV EAX, [totalRequests] // load memory for tot Requests into register INC EAX // update register MOV [totalRequests], EAX // store updated value back to memory 第一个条件是存在可以从多个线程访问的内存位置。 通常,这些位置是全局/静态变量,或者是可以从全局/静态变量访问的堆内存。 每个线程都有其自己的函数/方法范围的局部变量的堆栈框架,因此只能从拥有该堆栈的一个线程访问这些局部函数/方法变量otoh(位于堆栈上)。 第二个条件是存在与这些共享内存位置关联的属性(通常称为invariant ),该属性必须为true或有效,程序才能正常运行。 在上面的示例中,属性是“