C#中的线程四(System.Threading.Thread)

1.最简单的多线程调用

System.Threading.Thread类构造方法接受一个ThreadStart委托,改委托不带参数,无返回值

 public static void Start1()
{
Console.WriteLine("this is main thread!:{0},{1}", System.Threading.Thread.CurrentThread.CurrentCulture, Thread.CurrentThread.Name);
System.Threading.ThreadStart start = Method1;
Thread thread = new Thread(start);
thread.IsBackground = true;
thread.Start();
Console.WriteLine("main thread other thing...");
}
public static void Method1()
{
Console.WriteLine("this is sub thread!:{0},{1}", System.Threading.Thread.CurrentThread.CurrentCulture, Thread.CurrentThread.Name);
Thread.Sleep(TimeSpan.FromSeconds());
Console.WriteLine("sub thread other thing...");
}

注意thread.IsBackground=true,利用Thread创建的线程默认是前台线程,即IsBackground=false,而线程池中的线程是后台线程。

 前台线程和后台线程的区别在于:当主线程执行结束时,若任然有前台线程在执行,则应用程序的进程任然处于激活状态,直到前台线程执行完毕;而换成后台线程,当主线程结束时,后台线程也跟着结束了。

2.给线程传送数据

这是使用ParameterizedThreadStart 委托来代替ThreadStart委托,ParameterizedThreadStart 委托接受一个带object的参数,无返回值

 public static void Start2()
{
Customer c = new Customer { ID = "aaa", Name = "name" };
Console.WriteLine("this is main thread!:{0},{1}", System.Threading.Thread.CurrentThread.CurrentCulture, Thread.CurrentThread.Name);
ParameterizedThreadStart start = Method2;
Thread thread = new Thread(start);
thread.Start(c);
Console.WriteLine("main thread other thing...");
}
public static void Method2(object o)
{
Console.WriteLine("this is sub thread!:{0},{1}", System.Threading.Thread.CurrentThread.CurrentCulture, Thread.CurrentThread.Name);
Console.WriteLine(o.ToString());
Thread.Sleep(TimeSpan.FromSeconds());
Console.WriteLine("sub thread other thing...");
}

由此实例可以看出,我们将一个Customer 实例传入了新线程中,新线程可以直接读取此参数的信息。
    当然还有另一种方法也可以将数据传入线程中,创建一个类,把线程的方法定义为实例方法,这样就可以初始化实例的数据,之后启动线程,还是看实例代码:

 public static void Start4()
{
Customer c = new Customer();
//调用同一个对象,从而实现资源共享
ThreadStart ts = c.Increase;
Thread[] tArray = new Thread[];
for (int i = ; i < ; i++)
{
tArray[i] = new Thread(ts);
tArray[i].Start();
}
for (int i = ; i < ; i++)
{
tArray[i].Join();
}
Console.WriteLine(c.Number.ToString());
}
public static void Method3(object o)
{
Customer c = o as Customer;
//若不上锁,所以每次结果都不同
//应该重新建立一个object进行上锁,因为外边还有可能访问到c这个实例
lock (c)
{
for (int j = ; j < ; j++)
{
c.Number++;
}
}
}

Customer类的定义如下:

 public class Customer
{
public int Number
{
get;
set;
}
public string ID
{
get;
set;
} public string Name
{
get;
set;
}
public Customer()
{
Number = ;
}
public void Increase()
{
object o = new object();
lock (o)
{
for (int i = ; i < ; i++)
{
Number++;
}
}
}
}

3.竞态条件

来看竞态条件的定义: 如果两个或多个线程访问相同的对象,或者访问不同步的共享状态,就会出现竞态条件。

竞态条件也是多线程编程的常犯的错误,如果代码不够健壮,多线程编码会出现一些预想不到的结果,我们来根据一个实例来看:

 public static void RaceCondition()
{
ThreadStart method = ChangeState;
//这里放出20个线程
for (int i = ; i < ; i++)
{
Thread t = new Thread(method);
t.Name = i.ToString() + "aa";
t.Start();
}
}
//2.线程调用的方法,改变状态值
public static void ChangeState()
{
for (int loop = ; loop < ; loop++)
{
int state = ;
if (state == )
{
//此处第一个线程进入后没来得及++操作,第二个线程又进入,此时第一个线程做了++操作,第二个
//线程继续++,state的值变成7
state++;
if (state == )
{
//没有试验成功
Console.WriteLine("state={0},loop={1}", state, loop);
Console.WriteLine("thread name:{0}", Thread.CurrentThread.Name);
}
//Console.WriteLine(state.ToString());
}
}
}

最简单的解决竞态条件的办法就是使用上锁-lock,锁定共享的对象。用lock语句锁定在线程中共享的变量state,只有一个线程能在锁定块中处理共享的state对象。由于这个对象由所有的线程共享,因此如果一个线程锁定了state,另一个线程就必须等待该锁定的解除。

 public static void ChangeState2()
{
object o = new object();
for (int loop = ; loop < ; loop++)
{
int state = ;
lock (o)
{
if (state == )
{
state++;
if (state == )
{
//没有试验成功
Console.WriteLine("state={0},loop={1}", state, loop);
Console.WriteLine("thread name:{0}", Thread.CurrentThread.Name);
}
}
}
}
}

 4.死锁

在死锁中,至少有两个线程被挂起,等待对方解除锁定。由于两个线程都在等待对方,就出现了死锁,线程将无限等待下去。

 5.几种同步方法

上面介绍了两种线程数据共享的办法,一旦需要共享数据,就必须使用同步技术,确保一次只有一个线程访问和改变共享状态。上面介绍了使用lock的方法防止竞态条件的发生,但是如果用不好的话会产生死锁。那么下面再介绍几种针对不同情况使用的线程同步方法。

(1)SyncRoot模式

下面创建一个类的两个版本,一个同步版本,一个异步版本

 public class GeneralDemo
{
public virtual bool IsSynchronized
{
get { return false; }
}
public static GeneralDemo Synchronized(GeneralDemo demo)
{
if (demo.IsSynchronized)
{
return new SyncDemo(demo);
}
return demo;
}
public virtual void DoThis()
{ }
public virtual void DoThat()
{ }
}
 //同步版本
private class SyncDemo : GeneralDemo
{
private object syncRoot = new object();
private GeneralDemo demo;
private int state = ; public int State
{
get { return state; }
set { state = value; }
}
public SyncDemo(GeneralDemo demo)
{
this.demo = demo;
}
public override bool IsSynchronized
{
get
{
return true;
}
}
public override void DoThat()
{
lock (syncRoot)
{
demo.DoThis();
}
}
public override void DoThis()
{
lock (syncRoot)
{
demo.DoThis();
}
}

需要注意的是在SyncDemo类中,只有方法是同步的,对于这个类的成员调用并没有同步,如果试图用SyncRoot模式锁定对属性的访问,对state的访问变成线程安全的,仍会出现竞态条件

即这样做是不可取的:

 //public int State
//{
// get { lock (syncRoot) { return state; } }
// set { lock (syncRoot) { state = value; } }
//}
最好的办法是把lock添加到调用State的地方,当然锁定状态递增还有一种更快的方式
(2)Interlocked
 public int State
{
get
{
return Interlocked.Increment(ref state);
}
}

(3)Monitor类

 public override void DoThis()
{
if (Monitor.TryEnter(syncRoot, ))
{
try
{
//acquired the lock
//synchroized region for syncRoot
}
finally
{
Monitor.Exit(syncRoot);
}
}
else
{
//didn't get the lock,do something else
}
}

C#中的线程四(System.Threading.Thread)的更多相关文章

  1. MVC4 + EF + System.Threading.Thread 出现的问题记录

    项目要求是页面监测到后台数据库用户数据(Users)变化,前台做出相应的响应和操作. 一.参考很多资料,大概有几种方式: 参考资料地址:http://www.cnblogs.com/hoojo/p/l ...

  2. 异常System.Threading.Thread.AbortInternal

    异常信息: System.Threading.ThreadAbortException: 正在中止线程. 在 System.Threading.Thread.AbortInternal() 在 Sys ...

  3. c# System.Threading.Thread

    using System; using System.Threading; // Simple threading scenario: Start a static method running // ...

  4. System.Threading.Thread的使用及传递参数等总结

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...

  5. 【Java中的线程】java.lang.Thread 类分析

    进程和线程 联想一下现实生活中的例子--烧开水,烧开水时是不是不需要在旁边守着,交给热水机完成,烧开水这段时间可以去干一点其他的事情,例如将衣服丢到洗衣机中洗衣服.这样开水烧完,衣服洗的也差不多了.这 ...

  6. .Net 指定时间段内定时执行的Windows服务(System.Threading.Thread)

    创建一个Windows服务项目:解决方案(右击)——> 添加 ——> 新建项目——>项目类型选择Windows——>模板选择Windows服务 ,如图: 编写Windows服务 ...

  7. 【.Net 学习系列】-- .Net 指定时间段内定时执行的Windows服务(System.Threading.Thread)

    创建一个Windows服务项目:解决方案(右击)——> 添加 ——> 新建项目——>项目类型选择Windows——>模板选择Windows服务 ,如图: 编写Windows服务 ...

  8. 【异常记录(九)】 System.Threading.ThreadAbortException: 正在中止线程

    报错如下: System.Threading.ThreadAbortException: Thread was being aborted. at System.Threading.Thread.Ab ...

  9. C#中假设正确使用线程Task类和Thread类

    C#中使用线程Task类和Thread类小结 刚接触C#3个月左右.原先一直使用C++开发.由于公司的须要,所地採用C#开发.主要是控制设备的实时性操作,此为背景. 对于C#中的Task和Thread ...

随机推荐

  1. ASP.NET c# textbox 正则表达式 文本框只允许输入数字(验证控件RegularExpressionValidator )

    <input type="text" name="test" onKeyUp="test1.value=(this.value=this.val ...

  2. EM最大期望化算法

    最大期望算法(Expectation-maximization algorithm,又译期望最大化算法)在统计中被用于寻找,依赖于不可观察的隐性变量的概率模型中,参数的最大似然估计. 在统计计算中,最 ...

  3. Oracle 11g 导库导不出空表问题

    Oracle11g 会遇到这样的问题,用exp整库导出的时候,会遇到这样的问题,库里的空表没办法导出 select * from all_all_tables aa where aa.owner='U ...

  4. Linux 查看进程、清理缓存、查看磁盘空间、查看宽带的命令

    一.查看进程 查看所有的进程命令:ps 查看指定的进程命令:ps -ef|grep java (java 指的是服务名称) 结束进程命令:kill -9  9028 (9028指的是PID) 二.清理 ...

  5. JavaScript (jquery) 数组去重的算法探讨

                                    方法很巧妙 但是要事先知道对应的name或其他属性名称 主键值只适用于已知数据对象进行调用: var arr1 = [{ name: ' ...

  6. js queue dequeue clearQueue stop

      一.queue( [queueName ], newQueue ) 操作欲执行队列方法 第一个参数是队列名称,不写的话默认是fx 第二个参数可以是一个函数数组,存放所有队列函数,也可以是一个回掉函 ...

  7. Python读取文本,输出指定中文(字符串)

    因业务需求,需要提取文本中带有检查字样的每一行. 样本如下: 1 投入10kVB.C母分段820闭锁备自投压板 2 退出10kVB.C母分段820备投跳803压板 3 退出10kVB.C母分段820备 ...

  8. 我与solr(六)--solr6.0配置中文分词器IK Analyzer

    转自:http://blog.csdn.net/linzhiqiang0316/article/details/51554217,表示感谢. 由于前面没有设置分词器,以至于查询的结果出入比较大,并且无 ...

  9. Codeforces Zip-line 650D 345Div1D(LIS)

    传送门 大意:给出一个序列,求修改一个数过后的最长上升子序列. 思路:可以用主席树在线搞,也可以用树状数组离线搞,明显后者好写得多.我们首先读取所有的询问,然后就把询问绑在给出的位置,然后我们正向做一 ...

  10. 创建Xml文件与修改Xml文件

    /// <summary> /// 修改节点 /// </summary> /// <param name="user">UserSafe 实体 ...