线程的特点

上周,我在研究多线程OS时,发现一个进程中可以包括多个线程。
这些线程轻巧,就像我那个朋友一样,基本不占用系统资源,只有一些必要的资源保证独立运行。
比如,线程控制块TCB,它记录着线程的状态、现场资源、执行堆栈和局部变量。

2 02 3 年,我了解到线程是独立调度和分派的基本单位,就像我在游戏中扮演的角色一样,可以独立行动。
而且,线程之间可以并发执行,就像我同时在多个任务中切换一样,充分利用处理机和设备的并行工作能力。

我还发现,线程可以共享进程资源,就像我和朋友共享零食一样。
我们都在同一个地址空间中,可以访问同一个进程的文件、定时器和信号量机构。
这让我想到,线程之间互相通信时,不必调用内核,就像我和朋友直接交流一样方便。

不过,有时候我也会觉得,这些概念太复杂了,算了,你看着办吧。

C# 线程的基本操作(一)

哎哟,这C的线程操作,说起来都是泪啊。
记得有一次,我写了个程序,想用线程来处理一些耗时的任务,结果线程控制没搞明白,整个程序就卡在那儿了。

那年我还在一家小公司做开发,项目里有个数据导入的功能,数据量挺大,我一开始想着用单个线程来处理,结果导入速度慢得要命。
后来我学了一个新招,就是用线程来加速这个任务。

创建线程的时候,我用了ThreadStart委托,简单直接。
代码是这样的:
csharp Thread myThread = new Thread(new ThreadStart(ImportData)); myThread.Start();
这看起来没问题,但是问题就出在导入数据的方法上。
那个方法里,我忘记处理异常了,结果线程一遇到异常就挂了。
当时我头都大了,找了半天才发现原来是这个原因。

然后我又学了一个新的东西,就是线程状态管理。
我知道了线程可以处于多种状态,比如未开始、运行中、等待等等。
我用了ThreadState属性来检查线程的状态,这样我就能知道线程是不是在正常运行。

csharp if (myThread.ThreadState == ThreadState.Running) { Console.WriteLine("线程正在运行"); }
但是,这还不够。
我还得处理线程的优先级。
有时候,我希望某些线程能优先执行,所以我设置了线程的优先级:
csharp myThread.Priority = ThreadPriority.Highest;
不过,这招也不保险,因为操作系统可能会忽略优先级设置。

最让我头疼的是线程同步。
我有一个共享资源,多个线程都要访问它,结果就出了死锁。
我试了lock关键字,但是用得不对,导致死锁了。
后来我仔细研究了Monitor类和Mutex类,才终于解决了这个问题。

csharp private static readonly object lockObj = new object(); lock (_lockObj) { // 操作共享资源 }
最后,我还学到了线程安全的重要性。
我用了线程安全集合,比如ConcurrentBag,来避免数据竞争。

总结一下,用C操作线程,得注意线程安全、资源释放、异常处理和避免死锁。
这些坑我都是亲自踩过的,现在说出来,希望能帮到你们。
别像我一样踩坑了,哈哈。

什么是线程 单独线程 多线程

线程这东西啊,说白了就是进程里头的一个执行流。
你想想,电脑里跑的程序叫进程,但进程里头还能分成更小的执行单元,这就是线程。
现在像Mac、Windows这些系统,都把线程当基本单位了。
Java里也离不开线程,连个小Applet都得靠多个线程跑起来。
比如paint()和update()这些方法,就是由专门的绘图和事件处理线程调用的,init()、start()这些方法呢,就是Applet自己控制的。

线程跟进程有点像,都是单顺序控制流,但线程轻很多。
它在程序整个环境里跑,能共享程序资源。
线程得有自己的东西,比如执行堆栈和程序计数器。
它执行的代码只在它自己的上下文中有用,所以有时候也叫"执行上下文"。

线程属性
1 . 线程体 所有操作都在线程体里头。
Java里,要么继承Thread类的run()方法,要么实现Runnable接口的run()方法。
线程创建好了,系统就会调用它的run()方法,run()方法里写的代码就是线程干的事儿。

2 . 线程状态 线程有几种状态:
新线程态:刚创建的线程,还没分配资源,只能启动或终止。

可运行态:start()方法让线程准备好跑,但未必真在跑。
系统会调度着来的。

非运行态:挂起、sleep了、等条件变量或者等I/O。

死亡态:run()结束了或者被stop()了,线程就没了。

3 . 线程优先级 Java是固定优先级调度,线程创建时继承原线程的优先级,可以改。
系统总选优先级高的跑,同优先级就轮着来。

4 . 幽灵线程 就是给同一个进程里的其他对象和线程提供服务的线程。
比如HotJava浏览器有个"后台图片阅读器",专门从文件或网络读图片。
它的run()方法通常是无限循环等请求。

5 . 线程组 每个线程都得属于一个线程组,方便整体操作。
比如一次性启动或挂起组里所有线程。
线程创建时可以指定组,或者系统自动分。

多线程程序
多线程的好处不用说了,但麻烦也挺多。
比如要同步:
用synchronized语句锁对象,保证操作顺序。
比如线程1 先访问数据区,线程2 后访问。

用wait()和notify()更复杂,比如一个线程等条件满足再干。

Java不提供Semaphore,Unix或WindowsNT里有,但Java用wait/notify就行。

死锁是个大问题。
Java没死锁检测,只能自己防。
简单方法是对资源编号,先拿小号的再拿大号的。

线程和进程比较

进程是资源分配单位,有PCB记录所有资源。
线程不涉及资源分配,共享进程资源。

进程切换要保存资源指针、地址空间,线程切换不用,因为共享地址空间,开销小。

进程调度是内核干的,线程内核和用户程序都能管。

线程适用范围

服务器文件管理、通信控制
前后台处理
异步处理
线程执行特性

状态:初始态(new后start前)、Runnable、阻塞/NonRunnable、退出(run结束或stop)。

优先级:可以用setPriority()设,高优先级先跑。

操作:派生、阻塞、激活、调度、结束。

线程分类

用户级线程:程序自己管,内核只管进程。

系统级线程:内核管,提供系统调用API让程序创建、执行线程。

举例
1 . Solaris
支持内核线程、轻权进程(LWP)、用户线程。
一个进程可以有用户线程,用户线程复用LWP,LWP对应内核线程。
用户线程调用系统服务时得"捆绑"到LWP上。

thr_create()创建用户级线程,可以设永久捆绑或临时捆绑。

lwp_create()创建LWP,但没直接"捆绑"的系统调用。

2 . Windows NT
线程上下文包括寄存器、核心栈、线程环境块、用户栈。

线程状态:就绪、备用、运行、等待、转换、终止。

API:CreateThread()创建线程,ExitThread()结束线程,SuspendThread()挂起,ResumeThread()恢复。

说实话,线程这东西用好了能提高效率,但用不好也容易出问题,比如死锁。
得好好设计,特别是同步这块儿。

进程和线程有什么区别?

进程是资源分配单位,线程是CPU调度单位。

进程有PCB、程序段、数据段。
线程共享进程资源,可并发执行。

一个进程有默认线程,可动态增删线程。

操作系统运行实例是进程。
进程分就绪、运行、阻塞状态。

别混为一谈,按需创建线程。