黑马程序员技术交流社区
标题:
多线程之intelocked互锁
[打印本页]
作者:
hehe04
时间:
2012-8-26 18:25
标题:
多线程之intelocked互锁
本帖最后由 hehe04 于 2012-8-26 19:21 编辑
这两天学习多线程的内容,其中有一个很重要的概念,那就是互锁。当多个线程在运行时需要使用到同一资源,那么就需要使用互锁。例如,提示用户输入一句话,然后一个字一个字的将其打印在屏幕上。那么我们需要一个char类型的变量 char1,两个线程,一个用于对char1赋值,一个用于读取char1的值。,我们设计如下代码来实现上述需求。
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace 线程同步interlocked
{
class Program
{
private static char result;
private static string a = "青青子衿,悠悠我心!";
static void Main(string[] args)
{
ThreadStart ts=write;
ThreadStart ts2 = read;
Thread readThread = new Thread(ts2);
Thread writeThread = new Thread(ts);
writeThread.Start();
readThread.Start();
}
static void write()
{
for (int i = 0; i < a.Length; i++)
{
result = a[i];
Thread.Sleep(20);
}
}
static void read()
{
for (int i = 0; i < a.Length; i++)
{
char b = result;
Console.Write(b);
Thread.Sleep(20);
}
}
}
}
复制代码
这样写,貌似没有问题,但是当我们运行程序是就会发现,输出的文字乱七八糟,并不是我们所输入的原文。这是因为两个线程的执行几率并不是完全等分的,那么我们就需要这样来实现,当写入线程在写入的时候,就锁定这个变量,此时不允许读取线程来读取内容,等写完了这个字符,再解锁。同样的,读取线程也是一样。
interlocked类的部分方法
read() 读取计数器的值
Increment() 使计数器增加1
Decrement()使计数器减小1;
Add() 使计数器增加指定的值
Exchange() 把计数器设置为指定的值
CompareExchange() 先把计数器和某个值进行比较,若相等,就把计数器设为指定值
代码如下。
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace 线程同步interlocked
{
class Program
{
private static char result;
private static string a = "青青子衿,悠悠我心!";
static void Main(string[] args)
{
ThreadStart ts=write;
ThreadStart ts2 = read;
Thread readThread = new Thread(ts2);
Thread writeThread = new Thread(ts);
writeThread.Start();
readThread.Start();
}
static long num = 0; //定义一个long变量用于计数,必须是long,因为interlocked的增加和减少计数器的方法的参数要求是long类型。
static void write()
{
for (int i = 0; i < a.Length; i++)
{
while (Interlocked.Read(ref num) == 1) //这里必须使用引用来传递参数,当计数器为1时就不断的让他sleep
{ Thread.Sleep(10); }
result = a[i];
Interlocked.Increment(ref num);//写完后就让计数器增加1
}
}
static void read()
{
for (int i = 0; i < a.Length; i++)
{
while (Interlocked.Read(ref num) == 0)
{ Thread.Sleep(10); }
char b = result;
Console.Write(b);
Interlocked.Decrement(ref num);//读取完就让计数器减少1
}
}
}
}
复制代码
通过以上代码,我们就可以正常的输出字符串内容了。这里有一个问题,如果我不使用interlocked,而是直接操作num的值,也可以正常输出内容。那么是否这也是一种互锁呢,可是在我学习的资料中,并没有提到我的这种方法。是不是我这种写法并没有实现互锁,只是在这种特定情况下,输出内容正常罢了。知道的同学麻烦告知一下,这里先谢过了。代码是这样写的
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace 线程同步interlocked
{
class Program
{
private static char result;
private static string a = "青青子衿,悠悠我心!";
static void Main(string[] args)
{
ThreadStart ts=write;
ThreadStart ts2 = read;
Thread readThread = new Thread(ts2);
Thread writeThread = new Thread(ts);
writeThread.Start();
readThread.Start();
}
static long num = 0;
static void write()
{
for (int i = 0; i < a.Length; i++)
{
//while (Interlocked.Read(ref num) == 1)
//{ Thread.Sleep(10); }
while (num == 1)
{ Thread.Sleep(10); }
result = a[i];
//Interlocked.Increment(ref num);
num += 1;
}
}
static void read()
{
for (int i = 0; i < a.Length; i++)
{
//while (Interlocked.Read(ref num) == 0)
//{ Thread.Sleep(10); }
while (num == 0)
{ Thread.Sleep(10); }
char b = result;
Console.Write(b);
num = num - 1;
//Interlocked.Decrement(ref num);
}
}
}
}
复制代码
作者:
瞿正峰
时间:
2012-8-29 09:59
num 最后那个中实现
也就是直接操作num的值
直接操作NUM是在内存中进行操作
InterLocked.Increment 是在 CPU寄存器内操作
InterLocked.Increment 区别在于 你开两个进程
能通过寄存器同步 ,而 直接操作NUM是在内存中操作
开两个进程 他们在内存中生成的NUM变量是无法共享的
作者:
许庭洲
时间:
2012-8-29 10:31
1. Interlocked类的成员来实现线程同步;
2. Interlocked类提供了同步对多个线程共享的变量的访问的方法;
3. Interlocked类提供了Increment和Decrement方法递增或递减某个变量并返回结果;
4. 如果我不使用interlocked,而是直接操作num的值可能会发生死锁;
5. 直接操作num只不过是通过设置标志位来判断线程间实现同步,一旦线程较多,程序会崩溃。
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2