惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

罗磊的独立博客
Cisco Talos Blog
Cisco Talos Blog
C
Check Point Blog
博客园_首页
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Martin Fowler
Martin Fowler
Recorded Future
Recorded Future
S
Security @ Cisco Blogs
L
LINUX DO - 最新话题
博客园 - 司徒正美
P
Privacy International News Feed
G
Google Developers Blog
I
Intezer
Hacker News - Newest:
Hacker News - Newest: "LLM"
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
C
Cybersecurity and Infrastructure Security Agency CISA
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Scott Helme
Scott Helme
K
Kaspersky official blog
I
InfoQ
Y
Y Combinator Blog
T
The Blog of Author Tim Ferriss
Webroot Blog
Webroot Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
大猫的无限游戏
大猫的无限游戏
D
Docker
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
W
WeLiveSecurity
Microsoft Azure Blog
Microsoft Azure Blog
Spread Privacy
Spread Privacy
量子位
H
Hacker News: Front Page
Simon Willison's Weblog
Simon Willison's Weblog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
SecWiki News
SecWiki News
S
Security Affairs
Latest news
Latest news
人人都是产品经理
人人都是产品经理
C
CERT Recently Published Vulnerability Notes
S
Security Archives - TechRepublic
V
Visual Studio Blog
T
Troy Hunt's Blog
S
Secure Thoughts
F
Fortinet All Blogs
V
V2EX
The Register - Security
The Register - Security
J
Java Code Geeks
MongoDB | Blog
MongoDB | Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO

博客园 - 王庆

crosstool-ng搭建交叉编译环境注意事项 多重继承及虚继承中对象内存的分布 编写和调试Android下JNI程序流程 eclipse xml文件中按alt+/没有提示信息 Android NDK 工具链的使用方法(Standalone Toolchain) 编译Android VNC Server 使用gdb和gdbserver调试Android C/C++程序 openssl在多平台和多语言之间进行RSA加解密注意事项 LINUX开发使用的3个远程工具 NDK 链接第三方静态库的方法 动态生成程序集和类型 关于线程池的一段代码 理解ParseChildren用法 快速查找ASP.NET产生的临时文件 捕获ASP.NET程序发生的异常 Synchronized vs SyncRoot Exception vs ApplicationException 【转】Hashtable,ListDictionary,HybridDictionary比较 Monitor用法
C#多线程之Thread
王庆 · 2008-07-06 · via 博客园 - 王庆

.NET将关于多线程的功能定义在System.Threading名称空间中,因此,如果您的程序要使用多线程,必须引用此命名空间(using System.Threading)。
我们知道,在.NET中使用多线程有两种方式:
1,使用Thread创建一个新的线程。
2,使用ThreadPool。

首先我们先说说和Thread有关的几个概念。
1,创建线程和启动线程,如果代码可实现

Thread newThread = new Thread(new ThreadStart(Work.DoWork));
newThread.Start();

或者

Thread newThread = new Thread(new ParameterizedThreadStart(Work.DoWork));
newThread.Start(
42);

ParameterizedThreadStart 此委托在 .NET Framework 2.0 版中是新增的
在创建托管的线程时,在该线程上执行的方法将通过一个传递给 Thread 构造函数的 ThreadStart 委托或 ParameterizedThreadStart 委托来表示。
在调用 System.Threading.Thread.Start 方法之前,该线程不会开始执行。执行将从 ThreadStart 或 ParameterizedThreadStart 委托表示的方法的第一行开始。
ParameterizedThreadStart 委托和 Thread.Start(Object) 方法重载使得将数据传递给线程过程变得简单,但由于可以将任何对象传递给 Thread.Start(Object),因此这种方法并不是类型安全的。
将数据传递给线程过程的一个更可靠的方法是将线程过程和数据字段都放入辅助对象。

下面的代码示例演示通过静态方法和实例方法创建和使用 ParameterizedThreadStart 委托的语法,ThreadStart委托的使用方法和ParameterizedThreadStart一样,
唯一的区别在ThreadStart封装的方法不需要参数。(实例来自MSDN)

using System;
using System.Threading;

public class Work
{
    
public static void Main()
    
{
        
// To start a thread using a shared thread procedure, use
        
// the class name and method name when you create the 
        
// ParameterizedThreadStart delegate.
        
//
        Thread newThread = new Thread(
            
new ParameterizedThreadStart(Work.DoWork));
        
        
// Use the overload of the Start method that has a
        
// parameter of type Object. You can create an object that
        
// contains several pieces of data, or you can pass any 
        
// reference type or value type. The following code passes
        
// the integer value 42.
        
//
        newThread.Start(42);

        
// To start a thread using an instance method for the thread 
        
// procedure, use the instance variable and method name when 
        
// you create the ParameterizedThreadStart delegate.
        
//
        Work w = new Work();
        newThread 
= new Thread(
            
new ParameterizedThreadStart(w.DoMoreWork));
        
        
// Pass an object containing data for the thread.
        
//
        newThread.Start("The answer.");
    }

 
    
public static void DoWork(object data)
    
{
        Console.WriteLine(
"Static thread procedure. Data='{0}'",
            data);
    }


    
public void DoMoreWork(object data)
    
{
        Console.WriteLine(
"Instance thread procedure. Data='{0}'",
            data);
    }

}


/* This code example produces the following output (the order 
   of the lines might vary):

Static thread procedure. Data='42'
Instance thread procedure. Data='The answer'
*/

2,挂起线程
挂起线程分为两种,主动挂起和被动挂起。
主动挂起可表示为:
Thread.Sleep (Int32) 或 Thread.Sleep (TimeSpan) ,表示将当前调用线程挂起指定的时间。
被动挂起表示为:

Thread newThread = new Thread(new ThreadStart(Work.DoWork));
newThread.Start();
newThread.Join();


或者

Thread.CurrentThread.Join(50);

Join表示在继续执行标准的 COM 和 SendMessage 消息泵处理期间,阻止调用线程,直到某个线程终止为止。
在[STAThread]指示的Com线程模型中,我们应该使用Thread.CurrentThread.Join(50)这种方式。有一个与之有关的示例,
Thread.Sleep vs. Thread.CurrentThread.Join

3,终止线程
在调用 Abort 方法以销毁线程时,公共语言运行库将引发 ThreadAbortException。ThreadAbortException 是一种可捕获的特殊异常,但在 catch 块的结尾处它将自动被再次引发。
引发此异常时,运行库将在结束线程前执行所有 finally 块。由于线程可以在 finally 块中执行未绑定计算,或调用 Thread.ResetAbort 来取消中止,所以不能保证线程将完全结束。
如果您希望一直等到被中止的线程结束,可以调用 Thread.Join 方法。Join 是一个模块化调用,它直到线程实际停止执行时才返回。
注意:在托管可执行文件中的所有前台线程已经结束后,当公共语言运行库 (CLR) 停止后台线程时,它不使用 System.Threading.Thread.Abort。
因此,无法使用 ThreadAbortException 来检测 CLR 何时终止后台线程。
下面的示例说明如何中止线程。接收 ThreadAbortException 的线程使用 ResetAbort 方法取消中止请求并继续执行。(示例来自MSDN)

using System;
using System.Threading;
using System.Security.Permissions;

public class ThreadWork {
    
public static void DoWork() {
        
try {
            
for(int i=0; i<100; i++{
                Console.WriteLine(
"Thread - working."); 
                Thread.Sleep(
100);
            }

        }

        
catch(ThreadAbortException e) {
            Console.WriteLine(
"Thread - caught ThreadAbortException - resetting.");
            Console.WriteLine(
"Exception message: {0}", e.Message);
            Thread.ResetAbort();
        }

        Console.WriteLine(
"Thread - still alive and working."); 
        Thread.Sleep(
1000);
        Console.WriteLine(
"Thread - finished working.");
    }

}


class ThreadAbortTest {
    
public static void Main() {
        ThreadStart myThreadDelegate 
= new ThreadStart(ThreadWork.DoWork);
        Thread myThread 
= new Thread(myThreadDelegate);
        myThread.Start();
        Thread.Sleep(
100);
        Console.WriteLine(
"Main - aborting my thread.");
        myThread.Abort();
        myThread.Join();
        Console.WriteLine(
"Main ending."); 
    }

}

这段代码产生以下输出:
 Thread - working.
 Main - aborting my thread.
 Thread - caught ThreadAbortException - resetting.
 Exception message: Thread was being aborted.
 Thread - still alive and working.
 Thread - finished working.
 Main ending.

最后还有一点需要说明的是,在.NET Framework 2.0后,Thread对象的Suspend和Resume方法已被摈弃。
原因在于使用 Suspend 和 Resume 方法来同步线程的活动。您无法知道挂起线程时它正在执行什么代码。
如果您在安全权限评估期间挂起持有锁的线程,则 AppDomain 中的其他线程可能被阻止。
如果您在线程正在执行类构造函数时挂起它,则 AppDomain 中试图使用该类的其他线程将被阻止。很容易发生死锁。