c# 线程

名称空间:System.Threading

异步委托

异步委托使用线程池。基于IAsyncResult的异步模式。

static int TakesAWhile(int data, int ms)
{
}

public delegate int TakesAWhileDelegate(int data, int ms);

static void Main()
    TakesAWhileDelegate dl = TakesAWhile;
    IAsyncResult ar = dl.BeginInvoke(1, 3000, null, null);
    // (1)投票
    while (!ar.IsCompleted)
    {
          // doing something else in the main thread
          Thread.Sleep(50);
    }
    // (2) 等待句柄
   while (!ar.AsyncWaitHandle.WaitOne(50, false)) // 超时返回false
    {
         // doing something else in the main thread
    }
    int result = dl.EndInvoke(ar); // EndInvoke()方法会一直等待,直到委托完成其任务位置。

   // (3) 异步回调
   // (3-1) 回调函数
   dl.BeginInvoke(1, 3000, TakesAWhileCompleted, dl); // 最后一个参数可以使用ar.AsyncState读取
   // (3-2) Lambda表达式
   dl.BeginInvoke(1, 3000, 
         ar =>
         {
               int result = dl.EndInvoke(ar); // Lambda表达式可以直接访问该作用域外部的变量dl
         }
}

// 回调方法在委托线程中调用
static void TakesAWhileCompleted(IAsyncResult ar)
{
    if (ar == null) throw new ArgumentNullException("ar");
    TakesAWhileDelegate dl = ar.AsyncState as TakesAWhileDelegate;
    Trace.Assert(dl != null, "Invalid object type");
    int result = dl.EndInvode(ar); // 获得结果
} 


 Thread

static void Main()
{
    // (1) 委托参数为ThreadStart
    var t1 = new Thread(ThreadMain);
    t1.Start();
    // (2) 委托参数为ParameterizedThreadStart
    var d = new Data { Message = "Info" };
    var t2 = new Thread(ThreadMainWithParameters);
    t2.Start(d);
}

static void ThreadMain()
{
}

public struct Data
{
    public string Message;
}
static void ThreadMainWithParameters(Object o)
{
    Data d = (Data)o;
}


 

在默认情况下,用Thread类创建的是前台线程,线程池中的线程总是后台线程。Thread类创建时,可以设置IsBackground属性。

只要有一个前台线程在运行,应用程序的进程就在运行。

 

线程池

static void Main()
{
    ThreadPool.QueueUserWorkItem(JobForAThread); // 入池的线程只用于时间较短的任务,如果要一直运行,应使用Thread类创建一个线程
}

static void JobForAThread(Object state)
{
}

 

任务

任务后台使用ThreadPool。

(1)启动任务

static void TaskMethod()
{
}

static void Main()
{
    // using task factory
    TaskFactory tf = new TaskFactory();
    Task t1 = tf.StartNew(TaskMethod);
    // using task factory via a task
    Task t2 = Task.Factory.StartNew(TaskMethod);
    // using Task constructor
    Task t3 = new Task(TaskMethod);
    t3.Start();
}

(2)连续的任务

static void DoOnFirst()
{
}
static void DoOnSecond()
{
}
static void Main()
{
    Task t1 = new Task(DoOnFirst);
    Task t2 = t1.ContinueWith(DoOnSecond);
    Task t3 = t2.ContinueWith(DoOnError, TaskConinuationOptions.OnlyOnFaulted);
}

(3)任务的层次结构(父任务启动子任务,取消父任务也会取消子任务)


(4)任务的结果

(4-1)任务结束时,它可以把一些有用的状态写到共享对象,这个共享对象必须是线程安全的。

(4-2)使用Task类的泛型版本,定义返回某个结果的任务。

static Tuple<int, int> TaskWithResult(Object division)
{
}

static void Main()
{
    var t1 = new Task<Tuple<int, int>>(TaskWithResult, Tuple.Create<int, int>(8, 3));
    t1.Start();
    t1.Wait(); // wait the task to complete execution
    Console.WriteLine("result from task: {0} {1}", t1.Result.Item1, t1.Result.Item2);
}

Parallel类
定义了并行的for和foreach的静态方法Parallel.For()和Parallel.ForEach(),多次调用同一方法,迭代顺序没有定义。

// For方法的前两个参数定义了循环的开头和结束,第三个参数是一个Action<int>委托,整数参数代表循环的迭代次数
ParallelLoopResult result = Parallel.For(0, 10, i =>
    {
    });
ParallelLoopResult result = Parallel.For(0, 10, (int i, ParallelLoopState pls) =>
    {
        if (i > 15) pls.Break();
    });
// Parallel.ForEach()方法遍历实现了IEnumerable集合
string[] data = {"one", "two", "three"};
ParallelLoopResult result = Parallel.ForEach<string> (data, s =>
    {
    });
ParallelLoopResult result = Parallel.ForEach<string> (data, (s, pls, l) =>
    {
    });

Parallel.Invoke()调用多个方法并行运行

同步

争用条件:如果多个线程访问相同对象,或访问不同步的共享状态,就会出现争用条件。用lock解决:(1)锁定共享的对象,这可以在线程中完成;(2)将共享对象设置为线程安全的对象。

死锁:至少有两个线程被挂起,并等待对方解除锁定。避免死锁的方法:(1)从一开始就设计好锁定顺序;(2)为锁定定义超时时间。

同步技术:进程内:lock语句,Interlocked类,Monitor类;进程间:Mutex类,Semaphore类,Event类,ReaderWriterLockSlim类。

(1)lock语句

(1-1)对象锁:只有引用类型才能用于锁定。

(1-2)要锁定静态成员,把锁放在object类型上:

lock (typeof(StaticClass))

{

}

(1-3)用lock关键字可以将类的实例成员函数设置为线程安全的。

public class Demo  
{  
    private static readonly Object syncRoot = new Object();  
    public void DoThis()  
    {  
        lock(this.syncRoot)  
        {  
             // only one thread at a time can access DoThis  
        }  
    }
}  

reference:

http://blog.csdn.net/maths_bai/article/details/5999970

(1-4)可以创建类的两个版本,一个同步版本,一个异步版本。

public class Demo
{
    private class SynchronizedDemo : Demo
    {
        public int State { get; set; }
        private Object syncRoot = new Object();
        private Demo d;
        public SynchronizedDemo(Demo d)
        {
            this.d = d;
        }
        public override bool IsSynchronized
        {
            get { return true; }
        }
        public override void DoThis()
        {
            lock (this.syncRoot)
            {
                 d.DoThis();
            }
        }
    }
    public virtual bool IsSynchronized
    {
        get { return false; }
    }
    public static Demo Synchronized(Demo d)
    {
        if (!d.IsSynchronized)
        {
            return new SynchronizedDemo(d);
        }
        return d;
    }
    public virtual void DoThis()
    {
    }
}

在一个地方使用lock语句并不意味着,访问对象的其他线程都正在等待。必须对每个访问共享状态的线程显式地使用同步功能。

(2)Interlocked类

用于使变量的简单语句原子化,提供了以线程安全的方式递增、递减、交换和读取值的方法。

Interlocked.CompareExchange<SomeState>(ref someState, newState, null);

Interlocked.Increment(ref state);

 (3)Monitor类

Monitor.Enter(obj);
try
{
    // synchronized region for obj
}
finally
{
    Monitor.Exit(obj);
}

与lock语句相比,Monitor类的主要优点是:可以添加一个等待被锁定的超时值。

bool lockTaken = false;
Monitor.TryEnter(obj, 500, ref lockTaken);
if (lockTaken)
{
    try
    {
         // acquired the lock
         // synchronized region for obj
    }
    finally
    {
        Monitor.Exit(obj);
    }
}
else{
    // do something else
}

(4)WaitHandle抽象基类

用于等待一个信号的设置,可设置最长等待时间。

WaitOne()

static WaitAll()

static WaitAny()

Mutex, EventWaitHandle, Semaphore都派生自WaitHandle基类。
(5)Mutex类

互斥名字用于进程间共享

bool createdNew;
Mutex mutex = new Mutex(false, "ProMutex", out createdNew);

打开已有互斥Mutex.OpenExisting()

if (mutex.WaitOne()) // 获得互斥锁定,在该过程中成为该互斥的拥有者
{
    try
    {
          // synchronized region
    }
    finally
    {
        mutex.ReleaseMutex();
    }
}
else
{
    // some problem happened while waiting
}

由于系统能识别有名称的互斥,因此可以使用它禁止应用程序启动两次。


static void Main()
{
    bool createdNew;
    Mutex mutex = new Mutex(false, "SingletonMutex", createdNew);
    if (!createdNew)
    {
         Application.Exit();
         return;
    }
}

(6)Monitor和Mutex,只有一个线程能拥有锁定;Semaphore可以由多个线程使用,是一种记数的互斥锁定,可以定义允许同时访问受旗语锁定保护的资源的线程个数。。
Semaphore类和SemaphoreSlim类。 

static void Main()
{
    int threadCount = 6;
    int semaphoreCount = 4;
    var semaphore = new SemaphoreSlim(semaphoreCount, semaphoreCount);
    for (int i =0; i<threadCount; i++)
    {
        thread[i] = new Thread(ThreadMain);
        thred[i].Start(semaphore);
    }
    for (int i =0; i<threadCount; i++)
    {
        thread[i].Join();
    }
}

static void ThreadMain(object o)
{
    SemaphoreSlim semaphore = o as SemaphoreSlim;
    bool isCompleted = false;
    while (!isCompleted)
    {
         if (semaphore.Wait(600)
         {
               try
               {
                     // do synchronized job
               }
               finally
               {
                    semaphore.Release();
                    isCompleted = true;
               }
         }
         else
         {
              // timeout, wait again
         }
    }
}

(7)Events类

ManualResetEvent, AutoResetEvent, ManualResetEventSlim, CountdownEvent类,从托管代码中使用系统事件。事件可以发信号Set(),也可以不发信号Reset(),使用WaitHandle类,任务可以等待出于发信号状态的事件。

 

public class Calculator
{
    private ManualResetEventSlim mEvent;
    public int Result { get; private set; }
    public Calculator(ManualResetEventSlim ev)
    {
        this.mEvent = ev;
    }
    public void Calculation(object obj)
    {
        Tuple<int, int> data = (Tuple<int, int>)obj;
        Thread.Sleep(new Random().Next(3000));
        Result = data.Item1 + data.Item2;
        mEvent.Set();
    }
}

static void Main()
{
    const int taskCount = 4;
    var mEvents = new ManualResetEventSlim[taskCount];
    var waitHandles = new WaitHandle[taskCount];
    var calcs = new Calculator[taskCount];
    TaskFactory taskFactory = new TaskFactory();
    for (int i=0; i<taskCount; i++)
    {
        mEvents[i] = new ManualResetEventSlim(false);
        waitHandles[i] = mEvents[i].WaitHandle;
        calcs[i] = new Calculator(mEvents[i]);
        taskFactory.StartNew(calcs[i].Calculation, Tuple.Create(i+1, i+3));
    }
    
    for (int i=0; i<taskCount; i++)
    {
        int index = WaitHandle.WaitAny(mEvents);
        if (index == WaitHandle.WaitTimeout)
        {
           // timeout
        }
        else
        {
           mEvents[index].Reset();
           // get Result;
        }
    }
}

为了把一些工作分支到多个任务中,并在以后合并结果,使用CountdownEvent类,只需创建一个事件对象。

public class Calculator
{
    private CountdownEvent mEvent;
    public int Result { get; private set; }
    public Calculator(CountdownEvent ev)
    {
        this.mEvent = ev;
    }
    public void Calculation(object obj)
    {
        Tuple<int, int> data = (Tuple<int, int>)obj;
        Thread.Sleep(new Random().Next(3000));
        Result = data.Item1 + data.Item2;
        mEvent.Signal();
    }
}

static void Main()
{
    const int taskCount = 4;
    var cEvent = new CountdownEvent(taskCount);
    var calcs = new Calculator[taskCount];
    TaskFactory taskFactory = new TaskFactory();
    for (int i=0; i<taskCount; i++)
    {
        calcs[i] = new Calculator(mEvents[i]);
        taskFactory.StartNew(calcs[i].Calculation, Tuple.Create(i+1, i+3));
    }
    cEvent.Wait(); // Wait for all finished.
    for (int i=0; i<taskCount; i++)
    {
        // get Result;
    }
}


Timer 

(1)System.Threading.Timer在构造函数中传递一个委托。

private static void ThreadingTimer()
{
    var t1 = new System.Threading.Timer(TimeAction, null, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(3));
    Thread.Sleep(15000);
    t1.Dispose();
}

static void TimeAction(object o)
{
    Console.WriteLine("time: {0:T}", DateTime.Now);
}


(2)System.Timers.Timer组件,派生自Component基类,基于事件机制。

private static void TimersTimer()
{
    var t1 = new System.Timers.Timer(1000);
    t1.AutoReset = true;
    t1.Elapsed += TimeAction;
    t1.Start();
    Thread.Sleep(15000);
    t1.Stop();
    t1.Dispose();
}

static void TimeAction(object sender, System.Timers.ElapsedEventArgs e)
{
    Console.WriteLine("time: {0:T}", e.SignalTime);
}

 

 

 

 

 

 

 

 

 

 

 


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值