进程/线程/线程安全/静态类 杂谈

进程


是应用程序的一个实例要使用的资源的一个集合,每个进程都被赋予了一个虚拟空间,以确保另一个其它进程无法访问。

进程在者创建时需要分配大量的内存并且初始化加载EXE以及大量的DLL资源。

线程

相当于逻辑CPU用以解决进程长时间占用资源的问题,在创建时被分配大约1M的内存。线程以CPU时间片单位运行,当时间片到期后自动切换到另一个线程执行,从而缓解一个进程或线程长期占用资源的情况。线程切换伴随着上下文资源的切换,所以大量的线程切换也是浪费性能的事情。

一个进程拥有一个专用线程,理论上有多少进程最少就有多少线程,当然实际情况上一个进程可能拥有很多线程。我们可以通过任务管理器的添加选项列线程数来查看一个进程拥有多少线程。可以看出大部分进程的CPU使用率为零,但是线程却占据着大量内存资源。(一个线程栈要分配1M内存)。

一般进程的主线程会被标记[STAThread]属性指示应用程序的默认线程模型是单线程单元 (STA)。这个属性主要针对与COM
Interop互操作,如果在当前操作COM Interop对象的线程未标记STAThread或设置线程STAThread属性,则会出现异常。如果没有使用COM
Interop,一般不需要这个Attribute。

线程安全

只有在多个线程争夺共享资源并且进行破坏操作(如:写操作等)的情况才会有线程安全问题,如果多个线程在调用同一个实例的同一方法时并没出现资源争夺与破坏(如:只读),当然不会存在安全问题。但是大多数情况,非静态类的实例方法大都是操作某些属性字段资源,因此不可必免的出现对同一字段的资源的写操作,从而破坏了数据。同理,静态方法如果引用静态字段也会碰到线程安全的问题。判断一个方法是否线程安全,是看该方法是否存在对共享资源的争夺破坏。

静态类/静态字段/静态方法

静态构造函数(类型构造器)以互斥方式只被CLR执行一次,保证静态构造函数只被执行一次。

静态字段是非线程安全的,在多个线程中共享着同一个实例或静态类的静态字段。

静态方法在多个线程中为同一个实例或静态类的副本,所以是安全的。但是一理静态方法引用了静态字段,就不是线程安全了,因此应在静态方法必免使用静态字段,要么以互斥体的方式操作静态。

大多数据库操作类如SQLHelper此类都设计为静态类的,因为静态方法在不引用静态字段的前提下是线程安全的,所以基本上看到SQL
单连接的情况都是使用静态方法,可以防止单连接并发操作。

静态字段设计

定义静态字段时需要考虑线程安全

const常量定义(const在IL编译自动缀加static,所以不需要在static修饰),常量字段需要定义时就必须初始化一个值。

static readonly 只读静态变量 ,有一次构造初始化静态变量的机会。

当然你如果确实需要线程中修改静态变量的时,那就需要设计一个互斥锁或者InterLocked.CompareExchange方式操作。

静态事件

静态事件同非静态事件一样,区别就在于一个需要类实例化才能注册订阅,而另一个则是直接注册订阅。来看一下场景:

1.当A类(非静态事件)一个实例做一件事想同时通知X,Y,Z几个对象时,则我们要保证传递给X,Y,Z的A的实例必须是同一个。也就是说无论通过构造注入或者属性注入或者方法参数传递,都要保证是同一个A的实例,这样才能保证X,Y,Z注册到的是同一个事件。

但是如果A类是静态事件呢,则我们直接在X,Y,Z中直接注册订阅静态事件,并不需要解决同一个实例传递的问题。
想想如果有大量的不同的对象要通知,那如何保证同一个非静态事件的实例在这些对象中传递呢?

2.假如希望A类(非静态事件)的所有实例做的任何事情都通知到X,Y,Z ,那我们应该怎么做呢?
那肯定是要A所有实例的非静态事件都被X,Y,Z订阅,这样才能保证X,Y,Z接收到所有A实例事件触发的通知,但是想想这有多困难呢,你怎么知道A类会在哪些地方被实例化呢?并且还要在所有实例化的地方都要重复相同订阅的代码,这是否麻烦呢?我们看一下静态事件怎么解决这个问题的

假如A类使用了静态事件,而X,Y,Z则分别订阅了这个静态事件(只要针对静态事件订阅一次)。我们让A类的非静态方法完成时触发这个静态事件,想想会是什么情况?
不管A有多少实例化的对象,只要这些对象调用了非态方法触发了静态事件,则X,Y,Z都会收到通知。是不是简单多少了,不用担心A所有实例做的事件你不知道了。
这个应用场景很容易让人联想到数据库操作类,你想知道所有SQL操作,完全可以为你的数据库操作类设计一个静态事件的通知以便能在某个地方监控到的所有SQL语句。

以上两种情况可以看出,静态事件很容易的解决了一对多订阅以及多对一或多对多的订阅通知。当然我们也可以利用单例模式或者IOC容器容易的实现非静态事件分散通知的困难,但是要注意到一点静态字段不等同于静态类,单例模式以静态字段的形式保证了唯一实例,却很可能导致了线程的不安全。因为静态变量资源是被多个线程共享,你无法保证你的实例做为静态使用时,其中不会出资源争夺的情况发生。

lock/using/foreach/前台线程/后台线程


在多线程使用lock时,lock代码IL会自动编译为try..catch..finally...
,以确保在发生异常时lock可以正常解锁释放资源。相比Moniter.Entry与Monitr.Exit 就要自己解决异常释放锁的操作。

在using使用时也会自动封装try..catch..finally... ,在finally时会调用资源的Dispose释放对象资源.
foreach同样也是如此。

开启线程时,要注意设置前台线程还是后台线程,因为线程终结的方式不一样。

前台线程:进程在关闭时,必须等待前台线程执行完成。

后台线程:进程在关闭时,会直接终止后台线程,导致线程任务无法完成。

时间: 2024-11-07 11:52:17

进程/线程/线程安全/静态类 杂谈的相关文章

进程与线程杂谈

今天同事突然问我线程与进程的关系,虽然给她解释完,但是看她茫然的眼神,我就知道并没有解释清楚. 程序概述 谈进程与线程之前,我们先谈下什么是程序,程序是为实现特定目标或解决特定问题而用计算机语言编写命令序列的集合.说得通俗点就是你用计算机听得懂话(编程语言)命令计算机为你做特定的事情. 进程概述 在我理解中,一个进程就是一个程序的一次执行过程,如果要专业的话来说 进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体.

进程和线程

一.进程://进程用到的类Process,需要进行解析 using System.Diagnostics Process.Start("calc");//Process是非静态方法,括号里面是要开启的进程的名字 (静态方法与非静态方法区别:静态方法不用实例化对象,直接可以点出里面的方法) 弊端:有许多程序不知道它的运行名字到底是什么,如果写错了,就会出现程序崩溃错误 //选择程序 private void button1_Click(object sender, EventArgs e

linux查看某个进程的线程id(spid)

鉴于linux下线程的广泛使用 我们怎么查看某个进程拥有的线程id了 现在很多服务的设计 主进程->子进程->线程(比如mysql,varnish) 主进程负责侦听网络上的连接 并把连接发送给子进程 子进程派生线程去处理这些线程 mysql(父进程460,子进程863) 1 460 425 333 ? -1 S 0 0:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --datadir=/storage/mysql/backup --pid-file=/

该进程或线程自上一个步骤以来已更改

相关解决办法如下: VS进行高度时,断点处提示"该进程或线程自上一个步骤以来已更改" 每个断点跑两遍似的. 这个是由于在VS环境中 勾上了 "工具\选项--->调试--要求源文件与原始版本完全匹配"这个项 该进程或线程自上一个步骤以来已更改 英文表述:The process or thread has changed since last step 以下是是从网上摘录的解决办法. Q: I have a console application that exe

Python 中的进程、线程、协程、同步、异步、回调(一)

一.上下文切换技术 简述 在进一步之前,让我们先回顾一下各种上下文切换技术. 不过首先说明一点术语.当我们说"上下文"的时候,指的是程序在执行中的一个状态.通常我们会用调用栈来表示这个状态--栈记载了每个调用层级执行到哪里,还有执行时的环境情况等所有有关的信息. 当我们说"上下文切换"的时候,表达的是一种从一个上下文切换到另一个上下文执行的技术.而"调度"指的是决定哪个上下文可以获得接下去的CPU时间的方法. 进程 进程是一种古老而典型的上下文系

进程和线程、内核空间等概念

用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限.为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操作系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间.针对linux操作系统而言,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,而将较

进程和线程有什么区别?

作者:榴莲艺声链接:https://www.zhihu.com/question/21535820/answer/22915780来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 一.关于进程和线程,首先从定义上理解就有所不同 1.进程是什么? 是具有一定独立功能的程序.它是系统进行资源分配和调度的一个独立单位,重点在系统调度和单独的单位,也就是说进程是可以独 立运行的一段程序. 2.线程又是什么? 线程进程的一个实体,是CPU调度和分派的基本单位,他是比进程更小的

Python自动化开发,Day10 - 进程、线程、协程

本章内容 操作系统发展史介绍 进程与线程的区别 python GIL全局解释器锁 线程 语法 join 线程锁Lock\Rlock\信号量 将线程变为守护进程 Event时间 Queue队列 生产者消费者模型 进程 语法 进程间通讯 进程池 一.操作系统发展史介绍 手工操作(无操作系统) 1946年第一台计算机诞生--20世纪50年代中期,还未出现操作系统,计算机工作采用手工操作方式. 手工操作 程序员将对应于程序和数据的已穿孔的纸带(或卡片)装入输入机,然后启动输入机把程序和数据输入计算机内存

进程、线程和上下文切换

进程是什么? 狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed). 广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动.它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元. 进程的概念主要有两点:第一,进程是一个实体.每一个进程都有它自己的地址空间,一般情况下,包括文本区域(textregion).数据区域(data region