• 基元线程同步——内核模式构造


    基元线程同步——内核模式构造(WaitHandle,EventWaitHandle,AutoResetEvent,ManualResetEvent,Semaphore,Mutex)

    2012-08-29 17:46 by xiashengwang, 280 阅读, 0 评论, 收藏编辑

    一、内核模式构造

    内核模式构造,采用的是windows操作系统来同步线程,比用户模式的VolatileRead,VolatileWrite,Interlocked等同步慢很多。但它也有自己的优点:

    1,不用像用户模式那样占着cpu“自旋”,浪费cpu资源。

    2,内核模式可同步在同一机器不同进程中运行的线程

    3,可实现本地和托管线程相互之间的同步。

    4,一个线程可以一直阻塞,直到一个集合中的内核对象全部可用,或部分可用。(WaitAll,WaitAny)

    5,阻塞一个线程时,可以指定一个超时值,过了这个超时值就解除阻塞

    二、FCL提供的内核模式构造层次结构

    WaitHandle(抽象类)

        |——EventWaitHandle

             |——AutoResetEvent

             |——ManualResetEvent

        |——Semaphore

        |——Mutex

    他们都继承了WaitHandle抽象类,WaitHandle提供了下列共同的静态方法:

    WaitOne:阻塞调用线程,直到收到一个信号。

    WaitAny:阻塞调用线程,直到收到任意一个信号。

    WaitAll:阻塞调用线程,直到收到全部信号。

    SingleAndWait:向指定的内核对象发出信号,并等待另一个内核对象收到信号。

    Close/Dispose:关闭内核对象句柄。

    2.1 EventWaitHandle

    它属于事件(event),事件是内核维护的Boolean变量。如果事件为false,在事件上等待的线程就阻塞;如果事件为true,就解除阻塞。它主要有两个方法:

    Set:将事件设为true。

    ReSet:将事件设为false。

    注意:初始化的时候我们可以指定事件的初始值,比如下面的例子就是指定初始时事件为false。

                EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.AutoReset);//等同于AutoResetEvent
                EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.ManualReset);//等同于ManualResetEvent

    2.2 AutoResetEvent

    AutoResetEvent是EventWaitHandle的一个简单包装,内部没有额外的任何逻辑。它最大的特点就是,调用了Set方法将事件设为true之后,其中一个等待线程得到执行后,它会自动调用Reset方法,将事件信号设为false,以阻塞其它的线程。相当于放一个线程进来,门自动就关了(自动门)

    例子,使用AutoResetEvent实现一个简单的线程同步锁。

    复制代码
            private class SimpleWaitLock : IDisposable
            {
                //初始化一定要是true,否者,第一个调用Enter方法的线程会被阻塞
                private AutoResetEvent are = new AutoResetEvent(true);
    
                #region IDisposable 
    
                public void Enter()
                {
                    are.WaitOne();//第一个线程调用这个方法后,事件将会为false,其他线程会被阻塞
                    Console.WriteLine("thread={0}", Thread.CurrentThread.ManagedThreadId);
                }
                public void Exit()
                {
                    are.Set();//退出时,将事件信号设为true,放一个线程进来后,马上设为false(调用reset)
                }
                public void Dispose()
                {
                    are.Dispose();
                }
    
                #endregion
            }
    复制代码

    2.3 ManualResetEvent

    ManualResetEvent是EventWaitHandle的一个简单包装,内部也没有额外的任何逻辑。它和AutoResetEvent唯一的不同是,调用了Set方法将事件设为true后,不会去调用Reset方法,这将导致事件一直处于true,其它的多个线程都会得到执行,直到你手动调用Reset方法。相当于你把门打开后,需要手动去关(非自动门)

    2.4 Semaphore

    信号量(semaphore)是内核维护的一个Int32的变量。信号量为0时,在信号量上等待的线程会阻塞;信号量大于0时,就解除阻塞。它主要有1个方法:

    Release():就是一个加1的操作

    Release(int32 releasecount):就是一个加releasecount的操作。

    初始化semaphore时,可以指定最大和最小信号量的值。

    用Sempphore实现同样功能的同步锁:

    复制代码
            private class SimpleWaitLock : IDisposable
            {
                //初始化指定计数值为1,允许第一个线程可用
                private Semaphore sp = new Semaphore(1, 1);
    
                #region IDisposable
    
                public void Enter()
                {
                    sp.WaitOne();//第一个线程调用这个方法后,计数值减1,变为0,其他线程会被阻塞
                    Console.WriteLine("thread={0}", Thread.CurrentThread.ManagedThreadId);
                }
                public void Exit()
                {
                    sp.Release();//计数值加1,其他线程可用
                }
                public void Dispose()
                {
                    sp.Dispose();
                }
    
                #endregion
            }
    复制代码

    2.5 Mutex

    互斥体(mutex)和计数值为1的Semaphore或AutoResetEvent的工作方式非常相似。这三种方式每次都只释放一个等待的线程。主要方法:

    ReleaseMutex():计数减去1

    它有一个最大的不同是,它可以在同一线程上循环调用,也就是多次调用WaitOne(),然后在调用等次数的ReleaseMutex()。直到Mutex的计数为0时,其他等待的线程才能被调用。这种方式在平常中可能不太会用到。

    可以用Mutex来防止应用程序二次启动,这在平常工作中也经常会碰到。

    简单示例:

    复制代码
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
    
                bool createNew;
                Mutex mutex = new Mutex(false, "ApplicationGuidName", out createNew);
                //没有启动,就创建一个新的
                if (createNew)
                {
                    Application.Run(new Form1());
                }
                else
                {
                    // 已经启动了
                    MessageBox.Show("程序已经启动,不能重复启动!");
                }
            }
    复制代码

      注意:也可以用Semaphore和EventWaithandle来实现上面的功能,原理是一样的。但AutoResetEvent和ManualResetEvnet不行,他们没有提供类似的构造方法。

    2.6 在一个内核模式变得可用时调用一个方法

    可以通过ThreadPool.RegisterWaitForSingleObject方法注册一个方法。当一个事件收到信号,或是指定的时间超时,就会自动调用这个方法。

    这个方法对于AutoResetEvent特别有用。但不太适合ManualResetEvent,因为要手动去调用Reset方法,不然会无限的调用这个方法。

    复制代码
            private void TestAutoCallBack()
            {
                AutoResetEvent mre = new AutoResetEvent(false);
                //设定超时为2000ms
                ThreadPool.RegisterWaitForSingleObject(mre, new WaitOrTimerCallback(WaitCallBack),
                    "123", 2000, false);
    
                //发出一个信号
                mre.Set();
    
                //故意等代3000ms
                Thread.Sleep(3000);
            }
    
            //有信号或超时就会调用这个方法
            private void WaitCallBack(object state, bool timeOut)
            {
                Console.WriteLine("is time out = {0}", timeOut);
            }
    复制代码

    运行结果:

    is time out = False //得到信号时的调用
    is time out = True  //超时的调用
    is time out = True  //超时的调用
     
    分类: .NetC#
    标签: 线程同步

    随笔分类 -.Net

    基元线程同步——内核模式构造(WaitHandle,EventWaitHandle,AutoResetEvent,ManualResetEvent,Semaphore,Mutex)

    2012-08-29 17:46 by xiashengwang, 293 visits, 网摘收藏编辑
    摘要:一、内核模式构造内核模式构造,采用的是windows操作系统来同步线程,比用户模式的VolatileRead,VolatileWrite,Interlocked等同步慢很多。但它也有自己的优点:1,不用像用户模式那样占着cpu“自旋”,浪费cpu资源。2,内核模式可同步在同一机器不同进程中运行的线程。3,可实现本地和托管线程相互之间的同步。4,一个线程可以一直阻塞,直到一个集合中的内核对象全部可用,或部分可用。(WaitAll,WaitAny)5,阻塞一个线程时,可以指定一个超时值,过了这个超时值就解除阻塞。二、FCL提供的内核模式构造层次结构WaitHandle(抽象类) |——Event. 阅读全文

    基元线程同步——Interlocked Anything模式

    2012-08-29 14:19 by xiashengwang, 11 visits, 网摘收藏编辑
    摘要:上一篇基元线程同步——基础,非阻塞同步(VolatileRead,VolatileWrite,volatile,Interlocked)已经对Interlocked类做了比较详细的分析,这一篇是对Interlocked类的一个模式进行补充说明。如果没用过Interlocked类,可以看看上面的这篇文章。这个模式的名字是Jeffrey给起的,它究竟要解决什么问题,我们为什么要用它?带着这些疑问,我们来看看它的应用场景。看看下面这个设定最大值的例子: private static Int32 Maximum(ref int target, int value) { ... 阅读全文

    基元线程同步——基础,非阻塞同步(VolatileRead,VolatileWrite,volatile,Interlocked)

    2012-08-25 11:22 by xiashengwang, 12 visits, 网摘收藏编辑
    摘要:一、基元用户模式和内核模式。基元(Primitive):指代码中可以使用的最简单的构造。有两种基元构造:用户模式(user-mode)和内核模式(kernel-mode)。1,用户模式。它是用CPU指令来协调线程,这种协调是在硬件中发生的,所以速度会快于内核模式。但是也意味着,Windows操作系统永远也检测不到一个线程在一个基元用户模式构造上阻塞了。由于在一个基元用户模式构造上阻塞的线程永远不认为已经阻塞,所以线程池不会创建新的线程来替换这种阻塞的线程。另外,这些CPU指令只是阻塞线程极短的时间。缺点:只有Windows系统的内核才能停止一个线程的执行。用户模式中的线程可能会被系统抢占,但很 阅读全文

    线程同步——优势、劣势

    2012-08-25 10:16 by xiashengwang, 4 visits, 网摘收藏编辑
    摘要:一、线程同步好处:多个线程同时访问共享数据时,防止数据被损坏。二、线程同步带来的问题:1,实现比较繁琐,而且容易出错。必须对多个线程可能同时访问的所有数据,用额外的代码包围起来,以获得和释放一个同步锁。这需要由程序员来保证没有遗漏,对多线程共享的数据的加锁工作。并且,在程序完成时,需要进行压力测试以保证多个线程并发时,结果如预期。2,它会损害性能。获取和释放一个锁是需要时间的。因为需要额外的调用一些方法,并且需要协调调度下一个获得锁的线程。3,每次只能允许一个线程访问资源。这是锁的全部意义所在,但也是问题所在,因为阻塞一个线程可能会造成更多的线程被创建。三、线程同步建议:1,线程同步并不是一件 阅读全文

    研究BackgroundWorker后发现:AsyncOperation和SynchronizationContext的差异真的很大!

    2012-08-22 15:58 by xiashengwang, 47 visits, 网摘收藏编辑
    摘要:今天研究BackgroundWorker代码时发现,两处代码的写法有些不一致,于是好奇的测试了一番,以为能测出BackgroundWorker的一个bug。结果大家都知道microsoft胜了。下面来看看过程,BackgroundWorker类里的ReportProgress方法public void ReportProgress(int percentProgress, object userState){if (!this.WorkerReportsProgress) throw new InvalidOperationException("BackgroundWorker_Wo 阅读全文

    APM异步编程模型的优势

    2012-08-21 14:11 by xiashengwang, 10 visits, 网摘收藏编辑
    摘要:我们之所以要花大力气学习APM,就必须要清楚它能解决实际编程中的那些难题。以及现有的技术为什么不行。简单点说:APM是基于IAsyncResult接口的,采用的BeginXXX和EndXXX的形式来实现异步。下面这几点就是APM的优势:1,线程执行是异步的,不会阻塞调用线程。这一点也是我们使用异步的主要目的,我们不就是希望后台处理一些耗时操作吗?2,任务完成可以得到通知。(非阻塞)3,任务可以实现进度报告。(需要额外的辅助代码支持)4,可以有返回值。5,参数可以是多个。再看看Thread,ThreadPool,Task能实现上面的几点?这三个中,Task是相对完善的一个,对于第2点它可以通过C 阅读全文

    定时器Timer的选择

    2012-08-18 18:20 by xiashengwang, 8 visits, 网摘收藏编辑
    摘要:FCL提供了好几个Timer供我们选择,但却让很多人分不清他们的使用场合。下面来总结一下:System.Threading的Timer类。要在线程池上定时执行后台任务,他就是就好的选择。System.Windows.Forms的Timer类。这个类可以通过Vs的设计界面拖拽,它和UI线程是相关的,它使用的就是UI线程,所以在这里面执行UI更新的操作不会报线程非法访问的错。但是,如果在定时执行的函数里有长时间的运行任务,则会阻塞UI线程,造成界面”假死“。System.Windows.Threading的DispatcherTimer类。这个是System.Windows.Forms的Timer 阅读全文

    线程阶段性总结——APM,ThreadPool,Task,TaskScheduler ,CancellationTokenSource

    2012-08-18 16:39 by xiashengwang, 14 visits, 网摘收藏编辑
    摘要:不管我们使用thread,threadPool,task,还是APM异步,本质都是在使用多线程。对于新手来说,不太敢用多线程的原因,就我个人的体验来说,就是对多线程的异常捕获方式或时机缺乏了解,而一旦出现异常没有捕获,将会带来难以发现的bug,进而造成系统崩溃。而多线程本身也不是一朝一夕就能学好的,必须不断的去学习总结,所以我个人认为你要用一种线程模型,首先要对它有足够的了解,特别是对异常的捕获。如果你没有完全的把握,最好在实际开发中谨慎的用多线程。1,APM异步编程模型。采用BeginXXX和EndXXX方法。关于异常的捕捉,对于刚调用BeginXXX抛出的异常,异步操作可能还没有进入队列。 阅读全文

    颜色分段显示,线性填充的一个Demo

    2012-08-02 17:51 by xiashengwang, 852 visits, 网摘收藏编辑
    摘要:1,指定一个开始颜色,一个结束颜色,进行填充。2,生成指定数量的,这两个颜色中间的过渡色,这个对地图表示等功能需要分段颜色表示的很有用。效果图:先看第一个功能,填充渐变的颜色:主要就是利用LinearGradientBrush这个画刷 lblStartColor.Click += new EventHandler(lblColor_Click); lblEndColor.Click += new EventHandler(lblColor_Click); void lblColor_Click(object sender, EventA... 阅读全文

    GC垃圾回收——有用的函数和类

    2012-08-01 16:10 by xiashengwang, 35 visits, 网摘收藏编辑
    摘要:1,AddMemoryPressure和RemoveMemoryPressure 这两个方法主要用于本地资源,比如一个位图占用了50M本地内存,但是托管对象只包含一个HBitMap(4字节或8字节)。但CRL并不知道这个内存压力,它可能允许你分配数百个位图,因为它们占用的托管内存太少了。这两个方法的目的就是要告诉GC它实际的本地资源用了多少内存量,GC知道这个信息后会调整它的垃圾回收策略,当压力变大时,他就强制执行垃圾回收。 private void MemoryPressureDemo(int size) { //创建一组对象,并指定它们的... 阅读全文

    《CLR via C#》笔记——垃圾回收

    2012-07-31 20:58 by xiashengwang, 45 visits, 网摘收藏编辑
    摘要:本篇目录1,垃圾回收的基本概念 1.1 小对象堆和大对象堆 1.2 垃圾回收中的“代” 1.3 堆和“代”的关系2,啥时执行垃圾回收?3,垃圾回收器是如何工作的? 3.1标记无效对象。 3.2 压缩阶段。 3.3 终结揭秘4 ,Dispose模式:强制对象清理资源1,垃圾回收的基本概念1.1 小对象堆和大对象堆 我们都知道,CLR将我们的引用类型分配到托管堆上。这里指的托管堆实际是一个笼统的称呼。它实际是由一个小对象堆(small object heap,SOH)和一个大对象堆(large object heap,LOH)组成的。为对象分配空间时,将对象分为小对象(small object). 阅读全文

    《CLR via C#》笔记——异常和状态管理

    2012-07-30 12:48 by xiashengwang, 56 visits, 网摘收藏编辑
    摘要:目录一,定义异常二,异常处理机制 2.1 try块 2.2 catch块 2.3 finally块 2.4 CLS和非CLR异常三,System.Exception类四,抛出异常五,自定义异常类六,用可靠性换取开发效率七,指导原则和最佳实践 7.1 善用finally块 7.2 不要什么都捕捉 7.3 得体的从异常中恢复 7.4 从不可恢复的异常中回滚——维持状态 7.5 隐藏实现细节来维持契约八,未处理异常九,约束执行区(CER)十,代码契约一,定义异常 什么时候应该抛异常?当一个类型的成员(如方法,属性)不能完成任务时,就应抛出异常。面向对象的编程大大... 阅读全文

    《CLR via C#》笔记——可空值类型

    2012-07-20 18:15 by xiashengwang, 24 visits, 网摘收藏编辑
    摘要:一,可空值类型 顾名思义,这种类型支持null值。在FCL中被定义为System.Nullable<T>类型。这是一个结构体类型(struct),所以,不要认为System.Nullable<T>是一个引用类型,它仍然是一个值类型。要使用可空值类型,在代码中可以这样写: Nullable<Int32> x = 10; Nullable<Int32> y = null; Console.WriteLine("x: HasValue={0} Value={1}", x.HasValue, x.Value); C... 阅读全文

    《CLR via C#》笔记——线程基础

    2012-07-20 14:22 by xiashengwang, 43 visits, 网摘收藏编辑
    摘要:一,Windows为什么要支持线程 进程(process)是应用程序的一个实例要使用的资源的一个集合。每个进程都有一个虚拟化的地址空间,确保一个进程的代码不会被另外一个进程访问,这确保了应用程序的健壮性和安全性。但当应用程序执行一个无限循环,系统中又只有一个CPU时,他会执行无限循环,不能执行其他东西。为此,Mircorsoft引入了线程。线程(thread)的职责就是对CPU进行虚拟化,Windows为每个进程提供了该进程专用的线程。如果应用程序进入无限循环,与代码相关的进程会被“冻结”,但其他进程可以继续执行。二,线程开销线程会产生空间和时间上的开销。每个线程都包含以下要素:●线程内核对象 阅读全文

    《CLR via C#》笔记——运行时序列化(3)

    2012-07-18 20:54 by xiashengwang, 55 visits, 网摘收藏编辑
    摘要:七,流上下文 前面讲过,一组序列化好的对象可以有许多的目的地;同一进程,同一台机器的不同进程,不同机器的不同进程等。在一些比较少见的情况下,一个对象可能想知道他要在什么地方被反序列化,从而以不同的方式生成它的状态。例如:一个包装了Windows信号量(semaphore)的一个对象,如果它知道反序列化到同一个进程中,就可能决定序列化它的内核句柄(kernel handle),这是因为内核句柄在同一进程中有效。然而,如果它知道要反序列化到同一机器的不同进程中,就可能对信号量的字符串名称进行序列化。最后,如果对象知道它要反序列化到一台不同的机器上的一个进程中,就可能抛出异常,因为信号量值在同一台机 阅读全文

    《CLR via C#》笔记——运行时序列化(2)

    2012-07-18 20:52 by xiashengwang, 30 visits, 网摘收藏编辑
    摘要:五,格式化器如何序列化类型实例为了简化格式化的操作,FCL在System.Runtime.Serialization命名空间提供了一个FormatterServices类型。该类型只包含静态方法,而且不能被实例化。以下的步骤描述了格式化器如何自动序列化一个应用了SerializableAttribute的对象。1,格式化器调用FormatterServices的GetSerializableMembers方法:public static MemberInfo[] GetSerializableMembers(Type type,StreamingContext context)这个方法利用反射 阅读全文

    《CLR via C#》笔记——运行时序列化(1)

    2012-07-18 20:43 by xiashengwang, 32 visits, 网摘收藏编辑
    摘要:一,运行时序列化的作用序列化(Serialization)是将一个对象转换成一个字节流的过程。反序列化(Deserialization)是将一个字节流转换回一个对象的过程。在对象和字节流之间的转化是非常有用的机制。下面是一些例子。●应用程序的状态可以轻松保存到一个磁盘或数据库中,并在应用程序下次运行时恢复。Asp.net就是利用序列化和反序列化来保存和恢复会话状态的。●一组对象可轻松复制到剪贴板,在粘贴回同一个或另一个应用程序。事实上,Windows窗体和WPF就是利用了这个功能。●一组对象可以克隆放到一边作为“备份”;与此同时,用户操纵一组“主”对象。●一组对象可轻松地通过网络发给另一台机器 阅读全文

    《CLR via C#》笔记——AppDomain(2)

    2012-07-17 09:22 by xiashengwang, 47 visits, 网摘收藏编辑
    摘要:四,卸载AppDomain AppDomain很出色的一个能力就是它允许卸载。卸载AppDomain会导致CLR卸载AppDomain中的所有程序集,还会释放AppDomain的Loader堆。为了卸载一个AppDomain,可以调用AppDomain的静态方法UnLoad,这将导致CLR执行一系列的操作来卸载AppDomain。1,CLR挂起进程中执行过托管代码的所有线程。2,CLR检查所有线程栈,查看哪些线程正在执行要卸载的那个AppDomain中的代码,或者哪些线程会在某个时候返回至要卸载的那个AppDomain。在任何一个栈上,如果有准备卸载的AppDomain,CLR都会强迫对应的线 阅读全文

    《CLR via C#》笔记——AppDomain(1)

    2012-07-17 09:13 by xiashengwang, 42 visits, 网摘收藏编辑
    摘要:一,Appdomain概述 CLR COM服务器初始化时,会创建一个AppDomain。AppDomain是一组程序集的逻辑容器。宿主可以通过CLR创建额外的AppDomain。AppDomain的唯一作用就是隔离。下面是它的具体功能。●一个AppDomain中的代码创建的对象不能由另一个AppDomain中的代码直接访问。●AppDomain可以卸载。●AppDomain可以单独保护。AppDomain在创建后,会应用一个权限集,它决定了在这个AppDomain中运行的程序集的最大权限。●AppDomain可以单独实施配置。AppDomain在创建后,会关联一组配置设置。这些设置主要影响CL 阅读全文

    《CLR via C#》笔记——程序集的加载和反射(3)

    2012-07-16 17:54 by xiashengwang, 27 visits, 网摘收藏编辑
    摘要:五,使用反射发现类型的成员1,发现类型成员 字段,构造器,方法,属性,事件和嵌套类都可以被定义为类型的成员。FCL定义了一个System.Reflection.MemberInfo的抽象基类,封装了一组所有类型成员都通用的属性。从MemberInfo派生的一组类,每个类都封装了与一个特定类型成员相关的属性。下面是这个类型的层次结构。下面的程序演示如何查询一个类型的成员并显示与它们相关的信息。以下代码中,处理AppDomain中加载的所有程序集中的公共类型,对每个类型,调用GetMembers方法,并返回由MemberInfo派生对象构成的一个数组;对每个成员都显示他们的种类(字段,构造器,方法 阅读全文

    《CLR via C#》笔记——程序集的加载和反射(2)

    2012-07-16 17:41 by xiashengwang, 23 visits, 网摘收藏编辑
    摘要:四,设计支持加载项的应用程序 构建可扩展应用程序时,接口是中心。可以利用基类来代替接口,但接口通常是首选,因为它允许加载项开发人员选择他们自己的基类。下面描述了如何构建这样的应用程序。1,创建一个“宿主SDK”(Host SDK)程序集。它定义一个接口,接口的方法作为宿主应用程序和加载项应用程序之间的通信机制使用。接口的参数和返回类型,尝试使用MSCorLib.dll中定义的类型或接口。如果要传递并返回自己定义的数据类型,也应该在这个“宿主SDK”程序集中定义。一旦搞定接口的定义,就可以为这个程序集赋一个强名称(版本控制),然后把它打包并部署到合作伙伴或用户那里。一旦发布就应避免对该程序集的做 阅读全文

    《CLR via C#》笔记——程序集的加载和反射(1)

    2012-07-16 17:25 by xiashengwang, 40 visits, 网摘收藏编辑
    摘要:一,程序集加载 JIT编译器在将IL代码编译成本地代码时,会查看IL代码中引用了那些类型。在运行时,JIT编译器利用程序集的TypeRef和AssemblyRef元数据表的记录项来确定哪一个程序集定义了引用的类型。在AssemblyRef元数据记录项中记录了程序集强名称的各个部分—包括名称,版本,公钥标记和语言文化。这四个部分组成了一个字符串标识。JIT编译器尝试将与这个标识匹配的程序集加载到当前的AppDomain中。如果程序集是弱命名的,标识中将只包含名称。1,Assembly的Load方法 在内部CLR使用Assembly的Load方法来加载这个程序集,这个方法与Win32的LoadLi 阅读全文

    sscli2.0(Rotor) win7+vs2008编译

    2012-07-01 23:19 by xiashengwang, 12 visits, 网摘收藏编辑
    摘要:一,下载sscli2.0http://www.microsoft.com/en-us/download/details.aspx?id=4917二,编译sscli2.0需要安装Perlhttp://www.activestate.com/Products/ActivePerl/一路安装即可。三,解压sscli2.0后,需要修改一些文件,具体可参考这篇blog:http://blogs.msdn.com/b/jeremykuhne/archive/2008/02/19/sscli-2-0-and-visual-studio-2008.aspx唯一还要修改一个地方的是,打开env.core.pl文 阅读全文

    winForm 国际化的简单实现

    2011-12-23 14:17 by xiashengwang, 6 visits, 网摘收藏编辑
    摘要:国际化就是要实现多语种的界面切换。首先,我们不可能用if else等语句来根据选择的不同语种对所有的控件一个一个的设值,这样太麻烦了。.Net提供了国际化相关的支持,主要放在System.Globalization命名空间下。下面是一个简单的实现,麻雀虽小,五脏俱全。这个程序是最近写的一个程序,就在这基础上进行改造,关键是弄懂原理。1> 首先要加入Resource文件在VS工程-->添加新项目里加入三个resource文件,Resource文件的作用就是存放我们的界面控件的显示字符串。这里我们要实现3种语言的切换,所有加入了3个,分别命名为:Resource.en-US.resx, 阅读全文

    在for,foreach语句中小心使用控件的SendToBack,BringToFront方法

    2011-12-15 23:03 by xiashengwang, 5 visits, 网摘收藏编辑
    摘要:今天写了段VB。Net遍历控件的方法,乍一看没有什么问题,但结果却出人意料,control集合的元素没有遍历完,并且有重复的元素。 Public Sub SetControlLableAndPropertyFromXml(ByVal parent As Control) For Each subControl As Control In parent.Controls If subControl.HasChildren Then SetControlLableAndPropertyFromXml(subContro... 阅读全文

    《CLR via C#》笔记——CLR的执行模型

    2011-09-22 20:46 by xiashengwang, 12 visits, 网摘收藏编辑
    摘要:一.将源代码编译成托管代码1, CLR(Common Language Runtime)公共语言运行时是一个可由多种语言使用的“运行时”,CLR的核心功能(比如内存管理,程序集加载,安全性,异常处理和线程同步)可由面向CLR的所有语言使用。如“运行时”使用异常来报告错误,所以面向“运行时”的所有语言都能通过异常来报告错误。2, 可以将编译器视为语法检查器和“正确代码”的分析器,他们检查你的代码,确定你的一切都有一些含义,然后输出你对意图进行描述的代码,不同的编程语言允许不同的语法来开发。不要低估选择的价值。如对数学和金融领域,使用APL语法比用Perl表达同样的意图更节约开发时间。3, Mic 阅读全文

    Winform下KeyDown,KeyPress,KeyUp事件的总结

    2011-09-15 13:26 by xiashengwang, 16 visits, 网摘收藏编辑
    摘要:在winform程序中,经常会用到这几个事件用于控制数字输入,按键动作等操作,但一直没有完全弄清楚他们之间的区别和联系,到底什么时候用哪一个事件合适,闲暇无事,做了一个小小的总结,以免以后犯糊涂。1) 这三个事件调用的先后顺序(MSDN) 1.KeyDown :在控件有焦点的情况下按下键时发生 2. KeyPress :在控件有焦点的情况下按下键时发生。 3. KeyUp :在控件有焦点的情况下释放键时发生。2) KeyDown和KeyPress在MSDN上的解释完全一样,都是在按下键的时候发生,那区别是什么呢?textBox1_KeyDown(object sender, KeyEventA 阅读全文

    《CLR via C#》笔记——类型基础

    2011-06-01 16:25 by xiashengwang, 13 visits, 网摘收藏编辑
    摘要:一.所有类型都是从System.Object派生。1,下面两种类型定义完全一致://隐式派生自ObjectClass Employee{...}//显示派生自ObjectClass Employee:System.Object{…}2,System.Object的主要公共成员Equals:两个对象完全相同,返回true。GetHashCode:返回对象值的Hash码,当对象要在一个Hash表中作为Key使用时,必须重写这个方法。ToString:默认返回类型的完整名称(this.GetType().FullName),这个方法在继承类中经常都会被重写,如Int32,Boolean。ToStri 阅读全文

    VS编译时会将引用参照的dll所引用的子dll一起拷贝

    2011-06-01 16:20 by xiashengwang, 16 visits, 网摘收藏编辑
    摘要:今天发现一个很“怪异”的现象,用VS2008编译一个工程后,发现SVN目录的某些文件(几个dll文件)又变回以前的版本了,以为是SVN出了问题,重启机器后还是有这个问题。我的VS2008工程的输出路径是指向svn的本地拷贝路径的(这样,有修改了,就可以上传最新的程序),经过一番检查,发现不是SVN的问题,是VS2008编译的问题。工程中引用了一个Main.dll,每次编译都把它拷贝到输出目录,但Main.dll自身也引用了几个dll,在我的工程中只能看见一个Main.dll的引用,看不见它的子引用,当重新编译时,VS2008会将Main.dll引用的dll一起拷贝到svn目录,这样就出现了那个 阅读全文

    vs2008安装部署工程制作教程

    2011-05-19 12:22 by xiashengwang, 11 visits, 网摘收藏编辑
    摘要:vs2008安装部署工程制作教程1. 新建一个Class Library, 例如Name 为 CustomAction. 这个就是一个自定义安装行为的类。2. 添加安装类。在新建的Library里面添加一个 Installer Class,名字我暂时定为MyInstallerClassDll 3. 重写基类的函数 Commit Install OnAfterInstall OnAfterRollback OnAfterUninstall OnBeforeInstall OnBeforeRollback OnBeforeUninstall OnCommitted OnCommitting Rol 阅读全文
  • 相关阅读:
    python之路day10命名空间和作用域、函数嵌套,作用域链、闭包
    20200719 千锤百炼软工人第十四天
    20200720 千锤百炼软工人第十五 天
    JavaScript中基本数据类型和引用数据类型的区别
    js 经纬度坐标格式化 度分秒转度 度转度分秒
    export ,export default 和 import 区别 以及用法
    10月28日学习日志
    10月20日学习日志
    10月29日学习日志
    10月27日学习日志
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2662856.html
Copyright © 2020-2023  润新知