C# 多线程系列(二)
传递数据给一个线程
- 通过函数或lambda表达式包一层进行传递。
static void Main(string[] args) { Thread thread = new Thread(() => { threadOne("hello world"); }); thread.Start(); Console.ReadKey(); } static void threadOne(string content) { lib.print(content); }
- 另外一种方式是传递一个参数给Thread的Start方法:
static void Main(string[] args) { Thread thread = new Thread(threadOne); thread.Start("hello world"); Console.ReadKey(); } static void threadOne(object content) { lib.print(content); }
- 注意传递的数据的可靠性。
static void Main(string[] args) { for (int i = 0; i < 10; i++) { new Thread(() => { lib.put(i); }).Start(); } Console.ReadKey(); } //改示例输出的内容是不确定的,这里的问题是变量i在for循环执行时指向同一个内存地址。输出的过程中,i的值是在变化的。
//可以通过一个临时变量解决改进:
static void Main(string[] args) { for (int i = 0; i < 10; i++) { int temp = i; new Thread(() => { lib.put(temp); }).Start(); } Console.ReadKey(); } //变量temp在每个循环迭代中位于不同的内存块。因此每一个线程捕获到了不同的内存位置,而且没有问题。 //不过,这样输出输出的顺序也并非一定是0~9,以为不同线程的输出时间是不确定的。
命名线程
- 线程的Name属性,用于获取或设置线程的名称。包含线程名称的字符串,或者如果未设置名称,则为 null。Name属性设置后将无法修改,尝试修改会跑出System.InvalidOperationException
static void Main(string[] args) { Thread td = new Thread(threadOne); td.Name = "Thread:td"; //td.Name = "Thread:td0";打开将报错,name。 td.Start(); Thread td1 = new Thread(threadOne); td1.Name = "Thread:td1"; td1.Start(); Console.ReadKey(); } static void threadOne( ) { if (Thread.CurrentThread.Name == "Thread:td") { lib.print("[[ current thread is \"Thread:td\" ]]"); } else { lib.print(Thread.CurrentThread.Name); } }
前台线程和后台线程
- 默认情况下,显示创建的线程是前台线程。对于前台线程,只要其中任意一个正在运行,这个应用程序就一直存活。而后台线程不是这样的,一旦所有的前台线程完成,这个应用程序就结束了, 任何正在运行的后台线程立刻终止。
- 线程的IsBackground属性用于获取或设置一个值,该值指示某个线程是否为后台线程。如果此线程是后台线程或即将成为后台线程,则为 true;否则为 false。如果线程已经结束,访问IsBackground属性将跑出System.Threading.ThreadStateException异常。
- 当一个进程以这种方式终止,则任何后台线程执行栈里面的finally 语句块将会被规避。如果你的线程使用finally(or using)语句块去执行如释放资源或者删除临时文件的清理工作,这将是一个问题。为了避免这个,你可以显示地等待后台线程完成再退出应用程序。
- 一个线程前台/后台的状态跟它的优先级和配置的执行时间没有关联。
static void Main(string[] args) { Thread td = new Thread(() => { for (int i = 0; i < 100; i++) { Thread.Sleep(10); lib.put(i + " "); } }); td.IsBackground = true; td.Start(); //td.Join();打开此处将等到后台线程td跑完再结束程序,否则将直接结束。 }
线程优先级
- 一个线程的优先级决定了在操作系统中它可以得到多少相对其他线程的执行时间,下面是线程优先级的等级:
public enum ThreadPriority { Lowest = 0, BelowNormal = 1, Normal = 2, AboveNormal = 3, Highest = 4, }
当多线程同时是激活的,线程优先级是很重要的。
注意:提高线程优先级时,需要非常小心,这将可能导致其他线程对资源访问的饥饿状态的问题。
当提升一个线程的优先级时,不会使它执行实时工作,因为它被应用程序的进程优先级限制了。为了执行实时工作,你也必须通过使用System.Diagnostics的Process类来提升进程的优先级:
using (Process p = Process.GetCurrentProcess()) { p.PriorityClass = ProcessPriorityClass.High; }