巧妙地使用Interlocked的各个方法,再无锁无阻塞的情况下判断出所有线程的运行完成状态。

昨晚耐着性子看完了clr via c#的第29章<<基元线程同步构造>>,尽管这本书不是第一次看了,但是之前看的都是一带而过,没有深入理解,甚至可以说是不理解,实习了之后发现自己的知识原来这么表面,很多的实现都不能做出来,这很大程度上打击了我,而且,春招也快来了,更需要打扎实基础。引起我注意的是jeffrey在第29章说的:使用Interlocked,代码很短,绝不阻塞任何线程,二期使用线程池线程来实现自动伸缩。下载了源码,然后分析了下书中的示例,code如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks; namespace vlr_via_cs
{
internal static class AsyncCoordinatorDemo
{
public static void Go()
{
const Int32 timeout = ; // Change to desired timeout
MultiWebRequests act = new MultiWebRequests(timeout);
Console.WriteLine("All operations initiated (Timeout={0}). Hit <Enter> to cancel.",
(timeout == Timeout.Infinite) ? "Infinite" : (timeout.ToString() + "ms"));
Console.ReadLine();
act.Cancel(); Console.WriteLine();
Console.WriteLine("Hit enter to terminate.");
Console.ReadLine();
} private sealed class MultiWebRequests
{
// This helper class coordinates all the asynchronous operations
private AsyncCoordinator m_ac = new AsyncCoordinator(); // Set of Web servers we want to query & their responses (Exception or Int32)
private Dictionary<String, Object> m_servers = new Dictionary<String, Object> {
{ "http://cjjjs.com/", null },
{ "http://cnblogs.com/", null },
{ "http://www.jobbole.com/", null }
}; public MultiWebRequests(Int32 timeout = Timeout.Infinite)
{
// Asynchronously initiate all the requests all at once
var httpClient = new HttpClient();
foreach (var server in m_servers.Keys)
{
m_ac.AboutToBegin(); //确保先做三次加法, 若是有Sleep,在调用完这个函数后,执行
httpClient.GetByteArrayAsync(server).ContinueWith(task => ComputeResult(server, task));
} // Tell AsyncCoordinator that all operations have been initiated and to call
// AllDone when all operations complete, Cancel is called, or the timeout occurs
m_ac.AllBegun(AllDone, timeout);
} private void ComputeResult(String server, Task<Byte[]> task)
{
Object result;
if (task.Exception != null)
{
result = task.Exception.InnerException;
}
else
{
// Process I/O completion here on thread pool thread(s)
// Put your own compute-intensive algorithm here...
result = task.Result.Length; // This example just returns the length
} // Save result (exception/sum) and indicate that 1 operation completed
m_servers[server] = result;
m_ac.JustEnded();
} // Calling this method indicates that the results don't matter anymore
public void Cancel() { m_ac.Cancel(); } // This method is called after all Web servers respond,
// Cancel is called, or the timeout occurs
private void AllDone(CoordinationStatus status)
{
switch (status)
{
case CoordinationStatus.Cancel:
Console.WriteLine("Operation canceled.");
break; case CoordinationStatus.Timeout:
Console.WriteLine("Operation timed-out.");
break; case CoordinationStatus.AllDone:
Console.WriteLine("Operation completed; results below:");
foreach (var server in m_servers)
{
Console.Write("{0} ", server.Key);
Object result = server.Value;
if (result is Exception)
{
Console.WriteLine("failed due to {0}.", result.GetType().Name);
}
else
{
Console.WriteLine("returned {0:N0} bytes.", result);
}
}
break;
}
}
} private enum CoordinationStatus
{
AllDone,
Timeout,
Cancel
}; private sealed class AsyncCoordinator
{
private Int32 m_opCount = ; // Decremented when AllBegun calls JustEnded
private Int32 m_statusReported = ; // 0=false, 1=true
private Action<CoordinationStatus> m_callback;
private Timer m_timer; // This method MUST be called BEFORE initiating an operation
public void AboutToBegin(Int32 opsToAdd = )
{
Interlocked.Add(ref m_opCount, opsToAdd);
} // This method MUST be called AFTER an operations result has been processed
public void JustEnded()
{
if (Interlocked.Decrement(ref m_opCount) == )
ReportStatus(CoordinationStatus.AllDone);
} // This method MUST be called AFTER initiating ALL operations
public void AllBegun(Action<CoordinationStatus> callback, Int32 timeout = Timeout.Infinite)
{
m_callback = callback;
if (timeout != Timeout.Infinite)
{
// 在指定的时间点(dueTime) 调用回调函数,随后在指定的时间间隔(period)调用回调函数
m_timer = new Timer(TimeExpired, null, timeout, Timeout.Infinite);
}
JustEnded();
} // 处理过时的线程
private void TimeExpired(Object o) {
ReportStatus(CoordinationStatus.Timeout);
} public void Cancel()
{
if (m_callback == null)
throw new InvalidOperationException("Cancel cannot be called before AllBegun");
ReportStatus(CoordinationStatus.Cancel);
} private void ReportStatus(CoordinationStatus status)
{
if (m_timer != null)
{ // If timer is still in play, kill it
Timer timer = Interlocked.Exchange(ref m_timer, null);
if (timer != null) timer.Dispose();
} // If status has never been reported, report it; else ignore it
if (Interlocked.Exchange(ref m_statusReported, ) == )
m_callback(status);
}
}
} class Program
{
static void Main(string[] args)
{
AsyncCoordinatorDemo.Go(); Console.Read();
}
}
}

的确是无锁的操作,Interlocked方法是用户模式下的原子操作,针对的是CPU,不是线程内存,而且它是自旋等待的,耗费的是CPU资源。分析了下AsyncCoordinator类,主要就是利用Interlocked的Add方法,实时计数线程的数量,随后待一个线程运行的最后又调用Interlocked的Decrement方法自减。如果你留心的话,你会发现,目前绝大多数的并发判断中都用到了Interlocked的这些方法,尤其是interlocked的anything模式下的compareexchange方法,在这里提一嘴,除了compareexchange和exchange方法的返回值是返回ref类型原先的值之外,其余的方法都是返回改变之后的值。最后我们可以通过AllBegun方法来判断是不是所有的线程都执行完了,随后将状态变量m_statusReported设置为1,防止在进行状态判断。

这个类很好,之前写并发的时候,老是烦恼怎么判断并发是否已经完事了,又不想用到阻塞,这个类很好,当然应用到具体项目中可能还需要改,但是基本的模型还是这个,不变的。

有点感慨:好东西需要我们自己去发掘,之前查生产者消费者模型的时候,java代码一大堆,愣是没有看到几个C#,就算有也是简易,尽管可以把java的改变为C#的,但有点感慨C#的技术栈和资源少

使用Interlocked在多线程下进行原子操作,无锁无阻塞的实现线程运行状态判断的更多相关文章

  1. Erlang运行时中的无锁队列及其在异步线程中的应用

    本文首先介绍 Erlang 运行时中需要使用无锁队列的场合,然后介绍无锁队列的基本原理及会遇到的问题,接下来介绍 Erlang 运行时中如何通过“线程进度”机制解决无锁队列的问题,并介绍 Erlang ...

  2. java 多线程12 : 无锁 实现CAS原子性操作----原子类

    由于java 多线程11:volatile关键字该文讲道可以使用不带锁的情况也就是无锁使变量变成可见,这里就理解下如何在无锁的情况对线程变量进行CAS原子性及可见性操作 我们知道,在并发的环境下,要实 ...

  3. java多线程中的死锁、活锁、饥饿、无锁都是什么鬼?

    死锁.活锁.饥饿是关于多线程是否活跃出现的运行阻塞障碍问题,如果线程出现了这三种情况,即线程不再活跃,不能再正常地执行下去了. 死锁 死锁是多线程中最差的一种情况,多个线程相互占用对方的资源的锁,而又 ...

  4. JAVA多线程下高并发的处理经验

    java中的线程:java中,每个线程都有一个调用栈存放在线程栈之中,一个java应用总是从main()函数开始运行,被称为主线程.一旦创建一个新的线程,就会产生一个线程栈.线程总体分为:用户线程和守 ...

  5. 非阻塞同步算法与CAS(Compare and Swap)无锁算法

    锁(lock)的代价 锁是用来做并发最简单的方式,当然其代价也是最高的.内核态的锁的时候需要操作系统进行一次上下文切换,加锁.释放锁会导致比较多的上下文切换和调度延时,等待锁的线程会被挂起直至锁释放. ...

  6. 【Java并发编程】9、非阻塞同步算法与CAS(Compare and Swap)无锁算法

    转自:http://www.cnblogs.com/Mainz/p/3546347.html?utm_source=tuicool&utm_medium=referral 锁(lock)的代价 ...

  7. C#多线程编程(7)--锁

    一提到线程同步,就会提到锁,作为线程同步的手段之一,锁总是饱受质疑.一方面锁的使用很简单,只要在代码不想被重入的地方(多个线程同时执行的地方)加上锁,就可以保证无论何时,该段代码最多有一个线程在执行: ...

  8. 理解 Memory barrier(内存屏障)无锁环形队列

    原文:https://www.cnblogs.com/my_life/articles/5220172.html Memory barrier 简介 程序在运行时内存实际的访问顺序和程序代码编写的访问 ...

  9. java高并发程序设计模式-并发级别:阻塞、无障碍、无锁、无等待【转载】

    一般认为并发可以分为阻塞与非阻塞,对于非阻塞可以进一步细分为无障碍.无锁.无等待,下面就对这几个并发级别,作一些简单的介绍. 1.阻塞 阻塞是指一个线程进入临界区后,其它线程就必须在临界区外等待,待进 ...

随机推荐

  1. webStorm破解

    B4A73YYJ-eyJsaWNlbnNlSWQiOiI0M0I0QTczWVlKIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiIiw ...

  2. Python模块探秘之EasyGui

    在Windows想用Python开发一些简单的界面,所以找到了很容易上手的EasyGui库.下面就分享一下简单的使用吧. 参考的链接:官网Tutorial 接下来,我将从简单,到复杂一点点的演示如何使 ...

  3. ROS(indigo)MoveIt!控制ABB RobotStudio 5.6x 6.0x中机器人运动

    Gazebo以及相关参考文献,参考: ROS(indigo)ABB机器人MoveIt例子 这里需要配置RobotStudio,请参考ROS官网教程.下面列出要点:   window端配置结束后,在Ub ...

  4. JQuery实战---初识JQuery+入门实例

    JQuery在小编的世界中,也就是JavaScript和查询(Query),即是辅助JavaScript开发的库,百度百科对JQuery的介绍比较详细,小伙伴可以东东自己可耐的小爪子,上网进行搜索,说 ...

  5. [WinForm]最小化到系统托盘,右键退出

    1.拉出一个notifyIcon1到用户界面,也可以NEW一个 2.拉出一个ContextMenuStrip控件,命名为mymenu,集合中增加退出 3.notifyIcon1的属性ContextMe ...

  6. python3爬虫 - 利用浏览器cookie登录

    http://blog.csdn.net/pipisorry/article/details/47980653 爬虫爬网站不免遇到需要登录的问题. 登录的时候可能还会碰到需要填验证码的问题, 有的验证 ...

  7. javascript的介绍,实现和输出以及语法-javascript学习之旅(1)

    javascript的介绍 : 1.javascript死互联网最流行的脚本语言,可用于web和html,并且可用于服务器,pc和移动端 2.javascript脚本语言: 1.是一种轻量级的脚本语言 ...

  8. html5学习之旅-html5的简易数据库开发(18)

    实际上是模拟实现html5的数据库功能,用键值对的方式. !!!!!!废话不多说 ,代码 index.html的代码 <!DOCTYPE html> <html lang=" ...

  9. 12_Android中HttpClient的应用,doGet,doPost,doHttpClientGet,doHttpClient请求,另外借助第三方框架实现网络连接的应用,

     准备条件, 编写一个web项目.编写一个servlet,若用户名为lisi,密码为123,则返回"登录成功",否则"登录失败".项目名为ServerIth ...

  10. Java 与 C++ 不一样的地方(持续更新中...)

    本文仅以记录 Java 与 C++ 不同之处,以备随时查询. Java 程序运行机制 Java 是一门编译解释型的语言,即它在运行的过程中既需要编译也需要解释.如下图表示的是 Java 程序运行机制: ...