您的位置:首页 > 编程语言 > C#

C# 线程基础

2016-12-09 18:07 465 查看
1. 线程的基本概念 简单的讲进程就是程序分配在内存当中,等待处理器进行处理,请记住线程会消耗大量的操作系统资源。多个线程共享一个物理处理器将导致处理器忙于处理管理这些进程,而无法运行程序。 使用线程通常是一个操作系统的任务,试图在一个单核CPU上并行执行计算任务是没有任何意义的,可能比顺序执行花费的时间更长。 为了更好的利用现代处理器的能力,使用多线程处理程序发挥出最好的作用,这需要组织多个线程间的通讯和相互同步。 下面将学习一下 线程的生命周期,和创建线程、挂起线程、线程等待、以及终止线程。

创建一个线程操作

static void Main(string[] args)
{
//创建一个新的线程来实现输出数字
Thread t = new Thread(PrintNumber);
t.Start();
//这一行代码是在创建了一个新的线程并行执行的
PrintNumber();
Console.ReadLine();
}

static void PrintNumber()
{
Console.WriteLine("Starting...");
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
}

从上面代码可以看出一个程序始终有一个主线程在执行,而Thread是创建一个新的线程执行。两者之间是同步执行的。

暂停线程

static void Main(string[] args)
{
//创建一个带暂停的进程
Thread t = new Thread(PrintNumberWithdelay);
t.Start();
//这一行就是始终执行的主线程经过(一个程序都有一个始终执行的主线程)
PrintNumber();
}

static void PrintNumber()
{
Console.WriteLine("Starting...");
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
}
static void PrintNumberWithdelay()
{
Console.WriteLine("暂停...");
for (int i = 0; i < 10; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine(i);
}
}

很明显,主线程已经执行完毕,而新的线程在输出暂停以后还在继续执行。每次执行都会休眠2秒钟。

线程等待

那么如何不让主线程继续往下执行,而是等待新线程执行完毕再往下执行呢。

static void Main(string[] args)
{
//创建一个带暂停的进程
Thread t = new Thread(PrintNumberWithdelay);
t.Start();
t.Join();//线程等待
Console.WriteLine("执行完毕了");

}
static void PrintNumberWithdelay()
{
Console.WriteLine("暂停...");
for (int i = 0; i < 10; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(1));
Console.WriteLine(i);
}
}

终止线程

static void Main(string[] args)
{
//创建一个带暂停的进程
Thread t = new Thread(PrintNumberWithdelay);
t.Start();
Thread.Sleep(TimeSpan.FromSeconds(3));
t.Abort();//终止线程
Console.WriteLine("线程终止了");
}

这段代码是给线程注入了ThreadAbortException方法,导致线程被终结,这样操作是非常危险的,因为该异常可能会导致整个应用程序都崩溃。

可以使用 ResetAbort 方法来拒绝被终止。

检测线程状态

static void Main(string[] args)
{
//创建一个带暂停的进程
Thread t = new Thread(PrintNumberWithdelay);
Thread t1 = new Thread(DoNothing);
t1.Start();
t.Start();
for (int i = 0; i < 30; i++)
{
Console.WriteLine(t.ThreadState.ToString());
}
Thread.Sleep(TimeSpan.FromSeconds(3));
t.Abort();//终止线程
Console.WriteLine("线程终止了");
Console.WriteLine(t.ThreadState.ToString());
Console.WriteLine(t1.ThreadState.ToString());
}

static void PrintNumberWithdelay()
{
Console.WriteLine("开始啦...");
Console.WriteLine(Thread.CurrentThread.ThreadState.ToString());
for (int i = 0; i < 10; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(1));
Console.WriteLine(i);
}
}
static void DoNothing()
{
Thread.Sleep(TimeSpan.FromSeconds(2));
}

当主程序定义了两个不同的线程,一个将会被终止,而另一个则会成功运行。线程状态位于Thread 对象的ThreadState属性中。ThreadState属性是一个C#枚举对象。

刚开始线程状态为Unstarted ,然后启动线程,并估计在一周期为30的迭代的区间中,线程状会从Running变为WitSleepJoin。

线程优先级

class ThreadSample
{
private bool _isStopped = false;
public void Stop()
{
_isStopped = true;
}
public void CountNumbers()
{
long counter = 0;
while (!_isStopped)
{
counter++;
}
Console.WriteLine("{0} 和 {1,11}" + " count={2,13}",
Thread.CurrentThread.Name,
Thread.CurrentThread.Priority,
counter.ToString("NO"));
}
}

class Program
{
static void RunThreads()
{
var sample = new ThreadSample();
var threadOne = new Thread(sample.CountNumbers);
threadOne.Name = "ThreadOne";
var threadTwo = new Thread(sample.CountNumbers);
threadTwo.Name = "ThreadTwo";

threadOne.Priority = ThreadPriority.Highest;//优先级较高
threadTwo.Priority = ThreadPriority.Lowest;//优先级较低

threadOne.Start();
threadTwo.Start();

Thread.Sleep(TimeSpan.FromSeconds(2));
sample.Stop();

}
static void Main(string[] args)
{
Console.WriteLine("线程状态:{0}",Thread.CurrentThread.Priority);
Console.WriteLine("开始");
RunThreads();
Thread.Sleep(TimeSpan.FromSeconds(3));
Console.WriteLine("模拟CPU单核计算");
//让操作系统运行在第一个CPU第一个核心上
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1);
RunThreads();//运行时间很长
Console.WriteLine("线程终止了");
}

}

此程序只用于演示,通常中无需使用这种方式。

前台线程和后台线程

class ThreadSample
{
private readonly int _iterations;
public ThreadSample(int iterations)
{
_iterations = iterations;
}
public void CountNumbers()
{
for (int i = 0; i < _iterations; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine("{0} 和 {1}",
Thread.CurrentThread.Name, i);
}

}
}

class Program
{
static void Main(string[] args)
{
var samppleforegroud = new ThreadSample(10);
var sampplebackgroup = new ThreadSample(20);

var threadOne = new Thread(samppleforegroud.CountNumbers);

threadOne.Name = "前台";

var threadTwo = new Thread(sampplebackgroup.CountNumbers);

threadTwo.Name = "后台";
threadTwo.IsBackground = true;

threadOne.Start();
threadTwo.Start();

}

}

显示创建的是前台线程, ThreadTwo是后台线程 ,通过配置第一个线程会比第二个线程先完成,前台线程如果执行完毕,那么也会把后台线程终止掉。

向线程传递参数

class ThreadSample
{

private readonly int _iterations;
public ThreadSample(int iterations)
{
_iterations = iterations;
}
public void CountNumbers()
{
for (int i = 0; i < _iterations; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine("{0} 和 {1}",
Thread.CurrentThread.Name, i);
}

}
}

class Program
{
static void Count(object i)
{
CountNumbers((int)i);
}

static void CountNumbers(int number)
{
Console.WriteLine(number);
}

static void PrintNumber(int number)
{
Console.WriteLine(number);
}

static void Main(string[] args)
{
var samppleforegroud = new ThreadSample(10);

var threadOne = new Thread(samppleforegroud.CountNumbers);
threadOne.Name = "One";
threadOne.Start();
threadOne.Join();
Console.WriteLine("------------");

var threadTwo = new Thread(Count);
threadTwo.Name = "Two";
threadTwo.Start(8);
threadTwo.Join();

var threaThree = new Thread(() => CountNumbers(12));
threaThree.Name = "Three";
threaThree.Start();
threaThree.Join();

int i = 10;
var threaFour = new Thread(() => PrintNumber(i));
i = 20;
var threaFour1 = new Thread(() => PrintNumber(i));
threaFour.Start();
threaFour1.Start();

}

}

使用Lock

abstract class CountBase
{
public abstract void Increment();
public abstract void Decrement();

}

class Counter : CountBase
{
public int Count { get; private set; }

public override void Increment()
{
Count++;
}

public override void Decrement()
{
Count--;
}
}

class CounterWithLock : CountBase
{
private readonly object _syncroot = new object();

public int Count { get; private set; }
public override void Increment()
{
lock (_syncroot)
{
Count++;
}
}

public override void Decrement()
{
lock (_syncroot)
{
Count--;
}
}
}

class Program
{
static void TestCouner(CountBase c)
{
for (int i = 0; i < 100000; i++)
{
c.Increment();
c.Decrement();
}
}

static void Main(string[] args)
{
var c = new Counter();

var t1 = new Thread(() => TestCouner(c));
var t2 = new Thread(() => TestCouner(c));
var t3 = new Thread(() => TestCouner(c));

t1.Start();
t2.Start();
t3.Start();
t1.Join();
t2.Join();
t3.Join();

Console.WriteLine(c.Count);

var c1 = new CounterWithLock();

t1 = new Thread(() => TestCouner(c));
t2 = new Thread(() => TestCouner(c));
t3 = new Thread(() => TestCouner(c));

t1.Start();
t2.Start();
t3.Start();
t1.Join();
t2.Join();
t3.Join();

Console.WriteLine(c.Count);

}

}


使用Monitor 锁定资源

为了避免死锁,则使用Monitor 类 来避免死锁。

Monitor.TryEnter(lock1,TimeSpan.FromSeconds(5));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: