C#网络应用编程(学习记录一)

主线程与辅助线程

主线程

当一个程序启动时,就有一个进程被操作系统创建,与此同时系统也会为该进程创建一个默认的线程,该线程称为主线程(Main Thread)。常见:Main函数。当Main方法返回时,主线程自动终止

辅助线程

在一个进程中,除了主线程之外的其他线程都称为辅助线程

前台线程和后台线程

线程: 要么是前台线程,要么是后台线程

区别:后台线程不影响进程的终止, 前台线程则会影响到进程的终止

场景解析: 只有当属于某个进程的所有前台线程都终止后,公共语言库才会结束该进程,而且所有属于该进程的后台进程也都会立即停止,而不管后台工作是否完成

应用场景:
主线程——前台线程——界面显示和UI操作

辅助线程——后台线程——任务处理(数据处理、业务监视等)

具体操作:

  • 用Thread对象创建的线程默认都是前台线程;
  • 在托管线程池中的执行的线程默认都是后台线程
  • 从非拖管代码进入托管执行环节的所有线程也都被自动标记为后台线程

相关属性:

  • IsBackground属性: 获取或设置一个值,指示线程是否后台执行
  • IsThreadPoolThread属性:获取一个值,指示线程是否在托管线程池中执行,判断是不是属于托管线程池

创建线程

  • 位于System.Threading命名空间
  • 提供了Thread类可用于管理单独的线程
  • 通过Thread对象可创建一个单独的线程Thread t = new Thread(<方法名>)
Thread t1 = new Thread(Method1);
Thread t2 = new Thread(Method2);
......
public void Method1(){}
public void Method2(object obj){}
  • 通过委托实现线程创建
  • 使用哪种委托,要看定义的方法是否带参数
    上面的代码等价于
Thread t1 = new Thread(new ThreadStrat(Method1));
Thread t2 = new Thread(new ParameterizedThreadStart(Method2))
......
public void Method1(){}
public void Method2(Object obj){}

用Thread创建的线程默认为前台线程
如果希望将其作为后台线程,可将IsBackground属性设置为true

Thread t1 = new Thread(Method1);
t1.IsBackground = true;

后台线程优点: 优先级低, 占用资源相对较少等

用Thread创建线程的实例后,即可调用该实例的start方法启动该线程

在当前线程中调用Start方法启动另一个线程后,当前线程会继续执行后面的代码

Thread t1 = new Thread(Method1);
Thread t2 = new thread(Method2);
t1.start(); // 调用不带参数的方法
t2.start("MyString"); // 调用带参数的方法
public void Method1(){}
public void Method2(Object obj){}

线程终止

线程启动后,当不需要某个线程继续执行的时候,可以终止线程。
常用两种方法:

  1. volatile: 设置一个修饰符为volatile的布尔型的字段表示是否需要正常结束该线程 public volatile bool shouldStop; 线程中可以循环判断该布尔值,以确定是否退出当前线程。 其他线程中, 可以修改该布尔值通知是否希望终止该线程 此为实际中常用的方法
  2. Abort: 强行终止该线程的执行(属于非正常终止), 可能导致某个工作执行部内容就结束了

线程休眠

在多线程应用程序中,有时候不希望当前线程继续执行,而是希望其暂停一段时间。
调用Thread类提供的静态Sleep方法
Sleep方法将当前线程暂停(实际上是阻塞)指定的毫秒数

Thread.Sleep(1000);
# 该线程暂停的是当前线程;
# 无法从一个线程中暂停其他线程(存在安全隐患)

默认情况下, .NET框架都不允许在一个线程中直接访问另一个线程中的空间

如果两个或多个线程同时访问某以控件,可能会使该控件进入一种不确定的状态,甚至可能会出现死锁

WPF中的每个元素都有一个Dispatcher属性,自动在线程池中按优先级对工作项进行排队和调度
Dispathcer属性: 实现不同线程之间的交互而不会出现死锁问题

TextBoxName.Dispatcher.Invoke(...);
TextBoxName.Dispatcher.InvokeAsync(...);
# 该语句以同步或异步方法实现后台线程与界面元素(TextBox)之间的信息交互

同步/异步

  • 编写多线程并发程序时,需要解决多线程执行过程中的同步问题
  • 同步执行: CPU执行程序中,在执行某语句时,在该语句完成之前不会执行其后面的语句
  • 异步执行: CPU执行程序中,在执行某语句时, 不管该语句是否完成, 都会继续执行其后面的语句

资源同步

  • 当在某个线程中启动另一个或多个线程后,这些线程会同时执行,称为并行
  • 并行执行的多个线程同时访问某些资源时,必须考虑如何让多个线程保持同步
  • 线程同步的目的是防止多个线程同时访问某些资源时出现死锁和争用情况

死锁

死锁指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象, 若无外力作用, 它们都将无法推进下去。 线程运行中,典型的死锁例子是两个线程都停止响应, 并且都等待对方完成,从而导致任何一个线程都不能继续执行

争用

争用情况是当程序的结果取决于两个或多个线程中的哪一个先到达某一特定代码块时出现的错误
当线程出现争用情况是,多次运行同一个程序可能产生不同的结果,而且每次运行的结构都不可预知
例如,第一个线程正在读取字段,同时其他线程正在修改该字段,则第一个线程读取的值有可能不是该字段最新的值

资源同步方式

		三种方法
  1. 用volatile修饰符锁定公共或私有字段

可以实现单处理器或多处理器对共享字段的高效访问

利用volatile修饰符可以直接访问内存中的字段

所有处理器都可以访问该字段的最新值

private static volatile bool isStop=false

public static bool isStop{
get {
return isStop;}
set { isStop = value}
}
  1. 用InterLocked类提供的静态方法锁定局部变量
    此方法在 System.Threading.InterLocked类中
    通过加锁和解锁提供原子基本的静态操作方法
    并行执行过程中的某个局部变量进行控制, 实现同步:
int num = 0;
InterLocked.Increment(ref num);
InterLocked.Decrement(ref num);
  1. 用lock语句锁定代码块
    lock语句能确保当一个线程完成执行代码块之前,不会被其他线程中断
    被锁定的代码块称为临界区(代码不易过多)
    如果锁定的代码段中包含多个需要同步的字段或者多个局部变量,可以先定义一个私有字段lockedObject,通过一次性锁定该私有字段实现多个变量的同步操作
private Object lockedObj = new Object();
......
lock(lockedObj)
{......}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值