在本文中,我们将带你了解ReactOS源码分析(二)By:ProgrammeBoy在这篇文章中,我们将为您详细介绍ReactOS源码分析(二)By:ProgrammeBoy的方方面面,并解答react
在本文中,我们将带你了解ReactOS 源码分析 (二) By:ProgrammeBoy在这篇文章中,我们将为您详细介绍ReactOS 源码分析 (二) By:ProgrammeBoy的方方面面,并解答react源码深度解析 慕课网常见的疑惑,同时我们还将给您一些技巧,以帮助您实现更有效的.Net中的反应式编程(Reactive Programming)、8 Traits of an Experienced Programmer that every beginner programmer should know、Cg Programming/ProgrammableGraphics Pipeline、com.facebook.react.views.progressbar.ReactProgressBarViewManager的实例源码。
本文目录一览:- ReactOS 源码分析 (二) By:ProgrammeBoy(react源码深度解析 慕课网)
- .Net中的反应式编程(Reactive Programming)
- 8 Traits of an Experienced Programmer that every beginner programmer should know
- Cg Programming/ProgrammableGraphics Pipeline
- com.facebook.react.views.progressbar.ReactProgressBarViewManager的实例源码
ReactOS 源码分析 (二) By:ProgrammeBoy(react源码深度解析 慕课网)
重头戏FreeLdr.sys
简单介绍
代码位置:
先说下freeldr.sys,这个东东包含了内存管理、文件系统、缓存、UI、磁盘管理等要要的操作系统的功能。再加上点进程管理就可以成一个小操作系统了。那好我们就分析下freeldr以便我们能更好的理解操作系统。
来到代码目录下,好多代码,代码的入口函数在那个文件呀,怎么找呀。我啰嗦下,但不知道对不对,我们代开
像这样:
<?xml version="1.0"?>
<!DOCTYPE group SYstem "../../tools/rbuild/project.dtd">
<group xmlns:xi="http://www.w3.org/2001/XInclude">
<directory name="bootsect">
<xi:include href="bootsect/bootsect.rbuild" />
</directory>
<directory name="freeldr">
<xi:include href="freeldr/freeldr_startup.rbuild" />
<xi:include href="freeldr/freeldr_base64k.rbuild" />
<xi:include href="freeldr/freeldr_base.rbuild" />
<xi:include href="freeldr/freeldr_arch.rbuild" />
<xi:include href="freeldr/freeldr_main.rbuild" />
<xi:include href="freeldr/setupldr_main.rbuild" />
<xi:include href="freeldr/freeldr.rbuild" />
<xi:include href="freeldr/setupldr.rbuild" />
</directory>
<directory name="fdebug">
<xi:include href="fdebug/fdebug.rbuild" />
</directory>
</group>
看第一个是什么呀?对呀是: freeldr/freeldr_startup.rbuild,那就去子目录找下,找到了,内容如下:
<?xml version="1.0"?>
<!DOCTYPE module SYstem "../../../tools/rbuild/project.dtd">
<module name="freeldr_startup" type="objectlibrary">
<include base="freeldr_startup">include</include>
<include base="ntoskrnl">include</include>
<compilerflag>-fno-inline</compilerflag>
<compilerflag>-fno-zero-initialized-in-bss</compilerflag>
<directory name="arch">
</if>
<if property="ARCH" value="amd64">
<directory name="amd64">
<file first="true">fathelp.S</file>
<file>arch.S</file>
</directory>
</if>
</directory>
</module>
前面已经假定我们的机器是i386的了,看到带颜色的那几句吗?尤其是蓝色那句,好像是第一个程序源码的第一个文件到底是不是呢?我用IDA看了下freeldr的反汇编确实是.就是那个fathelp.asm,那好我们来看下fathelp.asm..
Fathelp.asm
代码路径: D:/ReactOS/ReactOS_src/boot/freeldr/freeldr/arch/i386/fathelp.asm
看到代码
; This code will be stored in the first 512 bytes
; of freeldr.sys. The first 3 bytes will be a jmp
; instruction to skip past the FAT helper code
; that is stored in the rest of the 512 bytes.
;
; This code is loaded at 0000:8000 so we have to
; encode a jmp instruction to jump to 0000:8200
global _mainCRTStartup ; For Mingw32 builds where the linker looks for this symbol
_mainCRTStartup:
global start
start:
db 0xe9
db 0xfd
db 0x01
看到这我就不分析下面的啦,正如上面的注释所说,这个代码储存在freeldr.sys的前512字节中,前3个字节会跳过这段代码,剩下的部分放在接下来的剩余空间内,这里为什么跳1fa呢?对呀,因为e9 01fd自身就3字节,加起来这好是0x200h,即512字节.
arch.s
那好我们看下一个文件,下一个文件是什么了?怎么看?不会这么快就忘了吧,在freeldr_startup.rbuild里呀!马上看下,哦是”arch.S”,咦?*.s是什么文件呢?不知道?我也不知道.那google呗.哈..知道了,原来也是汇编格式呀,只不过是AT&T汇编格式,和我们的nasm差不多,就是源/目的操作数的位置颠倒了下,这里我就不多说这个汇编的语法了,毕竟我们是分析代码嘛,大家可以去网上search下,大有文章在.
看代码:
.text
.code16
#define ASM
#include <arch.h>
#include <multiboot.h>
EXTERN(RealEntryPoint)
cli
xorw %ax,%ax
movw %ax,%ds
movw %ax,%es
movw %ax,%fs
movw %ax,%gs
movw %ax,%ss
/* Setup a stack */
movw stack16,%sp
sti
call switch_to_prot
.code32
xorl %eax,%eax
movl %eax,(_BootDrive)
movl %eax,(_BootPartition)
/* Store the boot drive */
movb %dl,(_BootDrive)
/* Store the boot partition */
movb %dh,(_BootPartition)
/* GO! */
pushl %eax
call _BootMain
call switch_to_real
.code16
INT
int $0x19
/* We should never get here */
stop:
jmp stop
nop
nop
/*
* Switches the processor to protected mode
* it destroys eax
*/
EXTERN(switch_to_prot)
.code16
cli /* None of these */
/* We don't kNow what values are currently */
/* in the segment registers. So we are */
/* going to reload them with sane values. */
/* Of course CS has to already be valid. */
/* We are currently in real-mode so we */
/* need real-mode segment values. */
xorw %ax,%ss
/* Get the return address off the stack */
popw (code32ret)
/* Save 16-bit stack pointer */
movw %sp,stack16
lgdt gdtptr
lidt i386idtptr
mov %cr0,%eax
orl $CR0_PE_SET,%eax
mov %eax,%cr0
/* Clear prefetch queue & correct CS */
ljmp $PMODE_CS,$inpmode
.code32
inpmode:
/* Setup segment selectors */
movw $PMODE_DS,%ss
movl stack32,%esp
/* Put the return address back onto the stack */
pushl (code32ret)
/* Now return in p-mode! */
ret
/*
* Switches the processor back to real mode
* it destroys eax
*/
EXTERN(switch_to_real)
.code32
/* We don't kNow what values are currently */
/* in the segment registers. So we are */
/* going to reload them with sane values. */
/* Of course CS has to already be valid. */
/* We are currently in protected-mode so we */
/* need protected-mode segment values. */
movw $PMODE_DS,%ss
/* Get the return address off the stack */
popl (code16ret)
/* Save 32-bit stack pointer */
movl %esp,stack32
/* jmp to 16-bit segment to set the limit correctly */
ljmp $RMODE_CS,$switch_to_real16
switch_to_real16:
.code16
/* Restore segment registers to correct limit */
movw $RMODE_DS,%ss
mov %cr0,%eax
andl $CR0_PE_CLR,%cr0
/* Clear prefetch queue & correct CS */
ljmp $0,$inrmode
inrmode:
movw %cs,%ss
/* Clear out the high 16-bits of ESP */
/* This is needed because I have one */
/* machine that hangs when booted to dos if */
/* anything other than 0x0000 is in the high */
/* 16-bits of ESP. Even though real-mode */
/* code should only use SP and not ESP. */
xorl %esp,%esp
movw stack16,%sp
/* Put the return address back onto the stack */
pushw (code16ret)
/* Load IDTR with real mode value */
lidt rmode_idtptr
sti /* These are ok Now */
/* Now return in r-mode! */
ret
/*
* Needed for enabling the a20 address line
*/
.code16
empty_8042:
.word 0x00eb,0x00eb // jmp $+2,jmp $+2
inb $0x64,%al
cmp $0xff,%al // legacy-free machine without keyboard
jz empty_8042_ret // controllers on Intel Macs read back 0xFF
testb $0x02,%al
jnz empty_8042
empty_8042_ret:
ret
/*
* Enable the A20 address line (to allow access to over 1mb)
*/
EXTERN(_EnableA20)
.code32
pushal
call switch_to_real
.code16
call empty_8042
movb $0xD1,%al // command write
outb %al,$0x64
call empty_8042
mov $0xDF,%al // A20 on
out %al,$0x60
call empty_8042
call switch_to_prot
.code32
popal
ret
/*
* disable the A20 address line
*/
EXTERN(_disableA20)
.code32
pushal
call switch_to_real
.code16
call empty_8042
movb $0xD1,$0x64
call empty_8042
mov $0xDD,%al // A20 off
out %al,$0x60
call empty_8042
call switch_to_prot
.code32
popal
ret
.code32
/* 16-bit stack pointer */
stack16:
.word STACK16ADDR
/* 32-bit stack pointer */
stack32:
.long STACK32ADDR
/* 16-bit return address */
code16ret:
.long 0
/* 32-bit return address */
code32ret:
.long 0
.p2align 2 /* force 4-byte alignment */
gdt:
/* NULL Descriptor */
.word 0x0000
.word 0x0000
.word 0x0000
.word 0x0000
/* 32-bit flat CS */
.word 0xFFFF
.word 0x0000
.word 0x9A00
.word 0x00CF
/* 32-bit flat DS */
.word 0xFFFF
.word 0x0000
.word 0x9200
.word 0x00CF
/* 16-bit real mode CS */
.word 0xFFFF
.word 0x0000
.word 0x9E00
.word 0x0000
/* 16-bit real mode DS */
.word 0xFFFF
.word 0x0000
.word 0x9200
.word 0x0000
/* GDT table pointer */
gdtptr:
.word 0x27 /* Limit */
.long gdt /* Base Address */
/* Initial GDT table pointer for multiboot */
gdtptrhigh:
.word 0x27 /* Limit */
.long gdt + INITIAL_BASE - FREELDR_BASE /* Base Address */
/* real-mode IDT pointer */
rmode_idtptr:
.word 0x3ff /* Limit */
.long 0 /* Base Address */
mb_info:
.fill MB_INFO_SIZE,1,0
cmdline:
.fill CMDLINE_SIZE,0
EXTERN(_BootDrive)
.long 0
EXTERN(_BootPartition)
.long 0
好,看完了,总结下…
这个文件里函数的调用基本步骤:
1,数据初始化
2,加载GDT
3,加载LDT
4,修改CR0的PE位进入保护模式
5,跳转到保护模式下
6,保存全局变量
7,调用_BootMain调用FreeLdr
8,修改CR0的PE位进入实模式
9,加载实模式的LDT
10,重新启动.
虽然下面的EnableA20和disableA20没用到吧,这里我也说下他们是干嘛的,其实代码作者也注释上了”to allow access to over 1mb”就是为访问大于1M的内存地址,参考《自己动手写操作系统》上的一段内容是:
什么是A20呢?这是一个历史问题,8086是采用SEG:OFFSET的模式分段的,所以他的最大内存是FFFF:FFFF即10FFEFh,但是8086只有20根地址总线,只能寻址到1Mb,如果试图访问超过1MB的地址时会怎样呢?实际上系统并不会发生异常.而是回卷回去,重新从地址0开始寻址,可是到了80286系列时,真的可以访问到1MB以上的内存地址了,如果遇到同样的情况系统不会再回卷寻址,这就造成了向上不兼容,为了保证百分之百兼容,IBM想出一个办法使用键盘来控制第20个地址位,这就是A20地址线,如果不开A20地址线总会是0.为了访问所有内存,我们需要打开A20地址线,默认是关闭的,但是怎么打开A20地址线呢?我们可以通过92h端口来达到目的..
知识点
.Net中的反应式编程(Reactive Programming)
系列主题:基于消息的软件架构模型演变
一、反应式编程(Reactive Programming)
1、什么是反应式编程:反应式编程(Reactive programming)简称Rx,他是一个使用LINQ风格编写基于观察者模式的异步编程模型。简单点说Rx = Observables + LINQ + Schedulers。
2、为什么会产生这种风格的编程模型?我在本系列文章开始的时候说过一个使用事件的例子:
var watch = new FileSystemWatcher(); watch.Created += (s,e) => { var fileType = Path.GetExtension(e.FullPath); if (fileType.ToLower() == "jpg") { //do some thing } };
这个代码定义了一个FileSystemWatcher,然后在Watcher事件上注册了一个匿名函数。事件的使用是一种命令式代码风格,有没有办法写出声明性更强的代码风格?我们知道使用高阶函数可以让代码更具声明性,整个LINQ扩展就是一个高阶函数库,常见的LINQ风格代码如下:
var list = Enumerable.Range(1,10) .Where(x => x > 8) .Select(x => x.ToString()) .First();
能否使用这样的风格来编写事件呢?
3、事件流
LINQ是对IEnumerable<T>的一系列扩展方法,我们可以简单的将IEnumerable<T>认为是一个集合。当我们将事件放在一个时间范围内,事件也变成了集合。我们可以将这个事件集合理解为事件流。
事件流的出现给了我们一个能够对事件进行LINQ操作的灵感。
二、反应式编程中的两个重要类型
事件模型从本质上来说是观察者模式,所以IObservable<T>和IObserver<T>也是该模型的重头戏。让我们来看看这两个接口的定义:
public interface IObservable<out T> { //Notifies the provider that an observer is to receive notifications. Idisposable Subscribe(IObserver<T> observer); }
public interface IObserver<in T> { //Notifies the observer that the provider has finished sending push-based notifications. void OnCompleted(); //Notifies the observer that the provider has experienced an error condition. void OnError(Exception error); //Provides the observer with new data. void OnNext(T value); }
这两个名称准确的反应出了它两的职责:IObservable<T>-可观察的事物,IObserver<T>-观察者。
IObservable<T>只有一个方法Subscribe(IObserver<T> observer),此方法用来对事件流注册一个观察者。
IObserver<T>有三个回调方法。当事件流中有新的事件产生的时候会回调OnNext(T value),观察者会得到事件中的数据。OnCompleted()和OnError(Exception error)则分别用来通知观察者事件流已结束,事件流发生错误。
显然事件流是可观察的事物,我们用Rx改写上面的例子:
Observable.FromEventPattern<FileSystemEventArgs>(watch,"Created") .Where(e => Path.GetExtension(e.EventArgs.FullPath).ToLower() == "jpg") .Subscribe(e => { //do some thing });
注:在.net下使用Rx编程需要安装以下Nuget组件:
Install-Package Rx-main
三、UI编程中使用Rx
Rx模型不但使得代码更加具有声明性,Rx还可以用在UI编程中。
1、UI编程中的第一段Rx代码
为了简单的展示如何在UI编程中使用Rx,我们以Winform中的Button为例,看看事件模型和Rx有何不同。
private void BindFirstGroupButtons() { btnFirstEventMode.Click += btnFirstEventMode_Click; } void btnFirstEventMode_Click(object sender,EventArgs e) { MessageBox.Show("hello world"); }
添加了一个Button,点击Button的时候弹出一个对话框。使用Rx做同样的实现:
//得到了Button的Click事件流。 var clickedStream = Observable.FromEventPattern<EventArgs>(btnFirstReactiveMode,"Click"); //在事件流上注册了一个观察者。 clickedStream.Subscribe(e => MessageBox.Show("Hello world"));
有朋友指出字符串“Click”非常让人不爽,这确实是个问题。由于Click是一个event类型,无法用表达式树获取其名称,最终我想到使用扩展方法来实现:
public static IObservable<EventPattern<EventArgs>> FromClickEventPattern(this Button button) { return Observable.FromEventPattern<EventArgs>(button,"Click"); } public static IObservable<EventPattern<EventArgs>> FromDoubleClickEventPattern(this Button button) { return Observable.FromEventPattern<EventArgs>(button,"DoubleClick"); }
我们平时常用的事件类型也就那么几个,可以暂时通过这种方案来实现,该方案算不上完美,但是比起直接使用字符串又能优雅不少。
btnFirstReactiveMode.FromClickEventPattern() .Subscribe(e => MessageBox.Show("hello world"));
2、UI编程中存在一个很常见的场景:当一个事件的注册者阻塞了线程时,整个界面都处于假死状态。.net中的异步模型也从APM,EAP,TPL不断演化直至async/await模型的出现才使得异步编程更加简单易用。我们来看看界面假死的代码:
void btnSecondEventMode_Click(object sender,EventArgs e) { btnSecondEventMode.BackColor = Color.Coral; Thread.Sleep(2000); lblMessage.Text = "event mode"; }
Thread.Sleep(2000);模拟了一个长时间的操作,当你点下Button时整个界面处于假死状态并且此时的程序无法响应其他的界面事件。传统的解决方案是使用多线程来解决假死:
BtnSecondEventAsyncModel.BackColor = Color.Coral; Task.Run(() => { Thread.Sleep(2000); Action showMessage = () => lblMessage.Text = "async event mode"; lblMessage.Invoke(showMessage); });
这个代码的复杂点在于:普通的多线程无法对UI进行操作,在Winform中需要用Control.BeginInvoke(Action action)经过包装后,多线程中的UI操作才能正确执行,WPF则要使用dispatcher.BeginInvoke(Action action)包装。
Rx方案:
btnSecondReactiveMode.FromClickEventPattern() .Subscribe(e => { Observable.Start(() => { btnSecondReactiveMode.BackColor = Color.Coral; Thread.Sleep(2000); return "reactive mode"; }) .SubscribeOn(ThreadPoolScheduler.Instance) .ObserveOn(this) .Subscribe(x => { lblMessage.Text = x; }); });
一句SubscribeOn(ThreadPoolScheduler.Instance)将费时的操作跑在了新线程中,ObserveOn(this)让后面的观察者跑在了UI线程中。
注:使用ObserveOn(this)需要使用Rx-WinForms
Install-Package Rx-WinForms
这个例子虽然成功了,但是并没有比BeginInvoke(Action action)的方案有明显的进步之处。在一个事件流中再次使用Ovservable.Start()开启新的观察者让人更加摸不着头脑。这并不是Rx的问题,而是事件模型在UI编程中存在局限性:不方便使用异步,不具备可测试性等。以XMAL和MVVM为核心的UI编程模型将在未来处于主导地位,由于在MVVM中可以将UI绑定到一个Command,从而解耦了事件模型。
开源项目ReactiveUI提供了一个以Rx基础的UI编程方案,可以使用在XMAL和MVVM为核心的UI编程中,例如:Xamarin,WFP,Windows Phone8等开发中。
注:在WPF中使用ObserveOn()需要安装Rx-WPF
Install-Package Rx-WPF
3、再来一个例子,让我们感受一下Rx的魅力
界面上有两个Button分别为+和-操作,点击+按钮则+1,点击-按钮则-1,最终的结果显示在一个Label中。
这样的一个需求使用经典事件模型只需要维护一个内部变量,两个按钮的Click事件分别对变量做加1或减1的操作即可。
Rx作为一种函数式编程模型讲求immutable-不可变性,即不使用变量来维护内部状态。
var increasedEventStream = btnIncreasement.FromClickEventPattern() .Select(_ => 1); var decreasedEventStream = btnDecrement.FromClickEventPattern() .Select(_ => -1); increasedEventStream.Merge(decreasedEventStream) .Scan(0,(result,s) => result + s) .Subscribe(x => lblResult.Text = x.ToString());
这个例子使用了IObservable<T>的”谓词”来对事件流做了一些操作。
- Select跟Linq操作有点类似,分别将两个按钮的事件变形为IObservable<int>(1)和IObservable<int>(-1);
- Merge操作将两个事件流合并为一个;
- Scan稍显复杂,对事件流做了一个折叠操作,给定了一个初始值,并通过一个函数来对结果和下一个值进行累加;
下面就让我们来看看IObservable<T>中常用的“谓词”
四、IObservable<T>中的谓词
IObservable<T>的灵感来源于LINQ,所以很多操作也跟LINQ中的操作差不多,例如Where、First、Last、Single、Max、Any。
还有一些“谓词”则是新出现的,例如上面提到的”Merge”、“Scan”等,为了理解这些“谓词”的含义,我们请出一个神器RxSandbox。
1、Merge操作,从下面的图中我们可以清晰的看出Merge操作将三个事件流中的事件合并在了同一个时间轴上。
2、Where操作则是根据指定的条件筛选出事件。
有了这个工具我们可以更加方便的了解这些“谓词”的用途。
五、IObservable<T>的创建
Observable类提供了很多静态方法用来创建IObservable<T>,之前的例子我们都使用FromEventPattern方法来将事件转化为IObservable<T>,接下来再看看别的方法。
Return可以创建一个具体的IObservable<T>:
public static void UsingReturn() { var greeting = Observable.Return("Hello world"); greeting.Subscribe(Console.WriteLine); }
Create也可以创建一个IObservable<T>,并且拥有更加丰富的重载:
public static void UsingCreate() { var greeting = Observable.Create<string>(observer => { observer.OnNext("Hello world"); return disposable.Create(() => Console.WriteLine("Observer has unsubscribed")); }); greeting.Subscribe(Console.WriteLine); }
Range方法可以产生一个指定范围内的IObservable<T>
Observable.Range(1,10) .Subscribe(x => Console.WriteLine(x.ToString()));
Generate方法是一个折叠操作的逆向操作,又称Unfold方法:
public static void UsingGenerate() { var range = Observable.Generate(0,x => x < 10,x => x + 1,x => x); range.Subscribe(Console.WriteLine); }
Interval方法可以每隔一定时间产生一个IObservable<T>:
Observable.Interval(TimeSpan.FromSeconds(1)) .Subscribe(x => Console.WriteLine(x.ToString()));
Subscribe方法有一个重载,可以分别对Observable发生异常和Observable完成定义一个回调函数。
Observable.Range(1,10) .Subscribe(x => Console.WriteLine(x.ToString()),e => Console.WriteLine("Error" + e.Message),() => Console.WriteLine("Completed"));
还可以将IEnumerable<T>转化为IObservable<T>类型:
Enumerable.Range(1,10).ToObservable() .Subscribe(x => Console.WriteLine(x.ToString()));
也可以将IObservable<T>转化为IEnumerable<T>
var list= Observable.Range(1,10).ToEnumerable();
六、Scheduler
Rx的核心是观察者模式和异步,Scheduler正是为异步而生。我们在之前的例子中已经接触过一些具体的Scheduler了,那么他们都具体是做什么的呢?
1、先看下面的代码:
public static void UsingScheduler() { Console.WriteLine("Starting on threadId:{0}",Thread.CurrentThread.ManagedThreadId); var source = Observable.Create<int>( o => { Console.WriteLine("Invoked on threadId:{0}",Thread.CurrentThread.ManagedThreadId); o.OnNext(1); o.OnNext(2); o.OnNext(3); o.OnCompleted(); Console.WriteLine("Finished on threadId:{0}",Thread.CurrentThread.ManagedThreadId); return disposable.Empty; }); source //.SubscribeOn(NewThreadScheduler.Default) //.SubscribeOn(ThreadPoolScheduler.Instance) .Subscribe( o => Console.WriteLine("Received {1} on threadId:{0}",Thread.CurrentThread.ManagedThreadId,o),() => Console.WriteLine("OnCompleted on threadId:{0}",Thread.CurrentThread.ManagedThreadId)); Console.WriteLine("Subscribed on threadId:{0}",Thread.CurrentThread.ManagedThreadId); }
当我们不使用任何Scheduler的时候,整个Rx的观察者和主题都跑在主线程中,也就是说并没有异步执行。正如下面的截图,所有的操作都跑在threadId=1的线程中。
当我们使用SubscribeOn(NewThreadScheduler.Default)或者SubscribeOn(ThreadPoolScheduler.Instance)的时候,观察者和主题都跑在了theadId=3的线程中。
这两个Scheduler的区别在于:NewThreadScheduler用于执行一个长时间的操作,ThreadPoolScheduler用来执行短时间的操作。
2、SubscribeOn和ObserveOn的区别
上面的例子仅仅展示了SubscribeOn()方法,Rx中还有一个ObserveOn()方法。stackoverflow上有一个这样的问题:What's the difference between SubscribeOn and ObserveOn,其中一个简单的例子很好的诠释了这个区别。
public static void DifferenceBetweenSubscribeOnAndobserveOn() { Thread.CurrentThread.Name = "Main"; IScheduler thread1 = new NewThreadScheduler(x => new Thread(x) { Name = "Thread1" }); IScheduler thread2 = new NewThreadScheduler(x => new Thread(x) { Name = "Thread2" }); Observable.Create<int>(o => { Console.WriteLine("Subscribing on " + Thread.CurrentThread.Name); o.OnNext(1); return disposable.Create(() => { }); }) //.SubscribeOn(thread1) //.ObserveOn(thread2) .Subscribe(x => Console.WriteLine("Observing '" + x + "' on " + Thread.CurrentThread.Name)); }
-
当我们注释掉:SubscribeOn(thread1)和ObserveOn(thread2)时的结果如下:
观察者和主题都跑在name为Main的thread中。
-
当我们放开SubscribeOn(thread1):
主题和观察者都跑在了name为Thread1的线程中
-
当我们注释掉:SubscribeOn(thread1),放开ObserveOn(thread2)时的结果如下:
主题跑在name为Main的主线程中,观察者跑在了name=Thread2的线程中。
-
当我们同时放开SubscribeOn(thread1)和ObserveOn(thread2)时的结果如下:
主题跑在name为Thread1的线程中,观察者跑在了name为Thread2的线程中。
至此结论应该非常清晰了:SubscribeOn()和ObserveOn()分别控制着主题和观察者的异步。
七、其他Rx资源
除了.net中的Rx.net,其他语言也纷纷推出了自己的Rx框架。
- RxJS: Javascript中的Rx
- RxCpp:C++中的Rx
- Rx.rb: Ruby中的Rx
- RxPy:python中的Rx
参考资源:
http://rxwiki.wikidot.com/101samples
http://introtorx.com/Content/v1.0.10621.0/01_WhyRx.html#WhyRx
http://www.codeproject.com/Articles/646361/Reactive-Programming-For-NET-And-Csharp-Developers
8 Traits of an Experienced Programmer that every beginner programmer should know
Referrence: http://whats-online.info/guides-and-info/36/Traits-of-Experienced-Programmer-that-every-beginner-should-know/
Not everybody has the capability to be a good programmer. Most lack the desire,others do not have a high level of practical aptitude and others lack the personality required to make a good programmer. To help you understand just what these ‘personality’ traits are,I will break down some of the traits that an experienced programmer has. Being in the field for 8 years Now,believe me I kNow the ups,downs,tricks and ‘’oh no’s’’ in this field. I will take you through 8 crucial traits of a programmer,which can be emulated by the beginners who wanna make it big in this field.
- Consistency
No programmer wants to be the wonder hit-and-disappear kind of a programmer. A good programmer is reliable. He kNows what it is that he wants,and is willing to keep on programming when need be. Not necessarily a 9-5 person,but one who accomplishes tasks and projects without leaving them hanging.
- Problem solver
As a programmer,I would liken programming to solving a complicated mathematics equations. They are complicated and most seem hard to crack. It is easy to just let go of them and look for a simpler equation to tackle. A programmer is that person who doesn’t give up on a task simply because it seems complicated. They look for solutions to every task. Giving up is a phrase that is never heard of in the world of programming.
- Planning skills
To plan is to see ahead. Instead of hopping into a new project,a good programmer will first study as much as he/ she can concerning the anticipated end product. As soon as that analysis is completed,the programmer ought to first strategize the project structure before inputting the first line of code. Planning goes hand in hand with consistency. So a consistent programmer is also a good planner.
- Excellent communication skills
I do not speak the perfect English,but am I good programmer? The answer is yes. Across the years,I have noticed that most of my peers are not fluent English speaker but they do pass for programmers with excellent communication skills. In programming,good communication skills is the ability to express an idea precisely and efficiently. Good programmers are able to pass their points across well. Programmers who experience a tough time conveying their points across or comprehending what others are telling them,may not be successful in the long run.
- Passion for Programming
This is the most important trait of all times. Passion is everything. Without the willingness to work,it will soon or later go down the drain. Some employed programmers only do the 9 to 5 job,for the salary part of it. These caliber of programmers do not program for long because they only do it for the cash,not for the work. When off from work,nothing close to what they do ever crosses their minds. You do not have to wake up,and go to bed breathing codes. Programmers who lack the passion are never enthused to acquire the best method of doing things and instead,they only engage in a routine,which is not be the best technique of doing things.
- Detail Oriented
This is what separates a patient programmer from an impatient one. Programming involves dealing with codes whose simple mistake Could cost you a whole project. A programmer who pays close consideration to detail will be suggestively more industrIoUs than the one who doesn‘t. This trait involves evaluation of self –conscIoUsness,which is very crucial for a serIoUs consistent programmer.
- Ability to cope with changing trends
Technology is constantly changing and the expertise and capabilities a programmer has currently will probably be out-of-date in the coming years. It is,therefore,key for a programmer to be able and willing to educate him/ herself and follow the up-to-date trends. This way,they find it easy to take part in any ongoing education chances that are presented.
- A good reader
A good programmer reads extensively. Not all the work is about coding. A substantial percentage of a programmer‘s work day is spent in reading. It Could be codes typed by other people,Web sites with examples,papers,or projects. Programmers who do not read extensively,or worse,do not comprehend what they are reading,are mostly incompetent at best,and hazardous at worst.
All in all,a good programmer
? Recognizes that programming is a resourceful art and is nothing interesting
? Takes boundless pride in his job and gets abundant contentment from it
? Attempts to decrease the difficulty of both the problem at hand and the result
? He/she utilizes his time but is never too occupied to help others hit the books
? He/she appreciates positive criticism and offers productive criticism for other programmers as well.
? Has Failed countless times but is always willing to learn from the failures.
? Makes his/her decisions without necessarily relying on other people. Sometimes someone needs to make decisions from his/ her heart without the influence of others.
? is continually learning and gets an excitement from those embarrassing moments. nothing is too serIoUs. Laugh at yourself at times.
Programming is not for the faint-hearted. Do not try programming at your desperation when everything else Could not work out. If you possess the above traits that a good programmer should have,then brace yourself for a life changing experience. Above all,hard work is everything.
Cg Programming/ProgrammableGraphics Pipeline
In the following diagrams,there is only one arrow between any two stages.However,it should be understood that GPUs usually implement the graphicspipeline with massive horizontal parallelism. Only software implementations ofthe graphics pipeline,e.g. Mesa 3D (see the Wikipedia entry),usually implement a single pipeline.
The vertex shader and fragment shader stages are discussed in more detail inthe platform-specific tutorials. The rasterization stage is discussed in Section“Rasterization” and theper-fragment operations in Section “Per-FragmentOperations”.
Vertex input parameters are defined based on the vertex data. Foreach vertex input parameter a semantic has to be defined,which specifies how the parameter relates to data in the fixed-functionpipeline. Examples of semantics are POSITION,COLOR,norMAL,TEXCOORD0,TEXCOORD1,etc. This makes it possible to use Cg programs even with APIs that wereoriginally designed for a fixed-function pipeline. For example,the vertexinput parameter for vertex positions should use the POSITION semanticsuch that all APIs can provide the appropriate data for this input parameter.Note that the vertex position is in object coordinates,i.e. this is theposition as specified in a 3D modeling tool.
com.facebook.react.views.progressbar.ReactProgressBarViewManager的实例源码
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( new ReactDrawerLayoutManager(),new ReacthorizontalscrollviewManager(),new ReactimageManager(),new ReactProgressBarViewManager(),new ReactRawTextManager(),new ReactScrollViewManager(),new ReactSwitchManager(),new ReactTextInputManager(),new ReactTextViewManager(),new ReactToolbarManager(),new ReactViewManager(),new ReactViewPagerManager(),new ReactTextInlineImageViewManager(),new ReactVirtualTextViewManager(),new SwipeRefreshLayoutManager(),new ReactWebViewManager()); }
@Override protected void setUp() throws Exception { super.setUp(); List<ViewManager> viewManagers = Arrays.<ViewManager>asList( new ReactViewManager(),new ReactProgressBarViewManager()); mUIManager = new UIManagerModule( getContext(),viewManagers,new UIImplementationProvider(),false); UiThreadUtil.runOnUiThread( new Runnable() { @Override public void run() { mUIManager.onHostResume(); } }); waitForIdleSync(); mInstance = ReactTestHelper.catalystInstanceBuilder(this) .addNativeModule(mUIManager) .addNativeModule(new AndroidInfoModule()) .addNativeModule(new DeviceInfoModule(getContext())) .addNativeModule(new AppStateModule(getContext())) .addNativeModule(new FakeWebSocketModule()) .addJSModule(ProgressBarTestModule.class) .build(); mRootView = new ReactRootView(getContext()); displayMetrics metrics = getContext().getResources().getdisplayMetrics(); mRootView.setLayoutParams( new FrameLayout.LayoutParams(metrics.widthPixels,metrics.heightPixels)); int roottag = mUIManager.addMeasuredRootView(mRootView); mInstance.getJSModule(ProgressBarTestModule.class).renderProgressBarapplication(roottag); waitForBridgeAndUIIdle(); }
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( ARTRenderableViewManager.createARTGroupViewManager(),ARTRenderableViewManager.createARTShapeViewManager(),ARTRenderableViewManager.createARTTextViewManager(),new ARTSurfaceViewManager(),new ReactDialogPickerManager(),new ReactDrawerLayoutManager(),new ReactDropdownPickerManager(),new FrescoBasedReactTextInlineImageViewManager(),new ReactWebViewManager(),new RecyclerViewBackedScrollViewManager(),new SwipeRefreshLayoutManager()); }
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( ARTRenderableViewManager.createARTGroupViewManager(),new SwipeRefreshLayoutManager()); }
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( ARTRenderableViewManager.createARTGroupViewManager(),new ReactModalHostManager(),new ReactSliderManager(),new SwipeRefreshLayoutManager()); }
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( ARTRenderableViewManager.createARTGroupViewManager(),new SwipeRefreshLayoutManager()); }
@Override protected void setUp() throws Exception { super.setUp(); List<ViewManager> viewManagers = Arrays.<ViewManager>asList( new ReactViewManager(),new UIImplementationProvider()); UiThreadUtil.runOnUiThread( new Runnable() { @Override public void run() { mUIManager.onHostResume(); } }); waitForIdleSync(); mInstance = ReactTestHelper.catalystInstanceBuilder(this) .addNativeModule(mUIManager) .addNativeModule(new AndroidInfoModule()) .addNativeModule(new FakeWebSocketModule()) .addJSModule(ProgressBarTestModule.class) .build(); mRootView = new ReactRootView(getContext()); displayMetrics metrics = getContext().getResources().getdisplayMetrics(); mRootView.setLayoutParams( new FrameLayout.LayoutParams(metrics.widthPixels,metrics.heightPixels)); int roottag = mUIManager.addMeasuredRootView(mRootView); mInstance.getJSModule(ProgressBarTestModule.class).renderProgressBarapplication(roottag); waitForBridgeAndUIIdle(); }
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { List<ViewManager> viewManagers = new ArrayList<>(); viewManagers.add(ARTRenderableViewManager.createARTGroupViewManager()); viewManagers.add(ARTRenderableViewManager.createARTShapeViewManager()); viewManagers.add(ARTRenderableViewManager.createARTTextViewManager()); viewManagers.add(new ARTSurfaceViewManager()); viewManagers.add(new ReactDialogPickerManager()); viewManagers.add(new ReactDrawerLayoutManager()); viewManagers.add(new ReactDropdownPickerManager()); viewManagers.add(new ReacthorizontalscrollviewManager()); viewManagers.add(new ReactimageManager()); viewManagers.add(new ReactModalHostManager()); viewManagers.add(new ReactProgressBarViewManager()); viewManagers.add(new ReactRawTextManager()); viewManagers.add(new ReactScrollViewManager()); viewManagers.add(new ReactSliderManager()); viewManagers.add(new ReactSwitchManager()); viewManagers.add(new FrescoBasedReactTextInlineImageViewManager()); viewManagers.add(new ReactTextInputManager()); viewManagers.add(new ReactTextViewManager()); viewManagers.add(new ReactToolbarManager()); viewManagers.add(new ReactViewManager()); viewManagers.add(new ReactViewPagerManager()); viewManagers.add(new ReactVirtualTextViewManager()); viewManagers.add(new ReactWebViewManager()); viewManagers.add(new SwipeRefreshLayoutManager()); SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(reactContext); if (preferences.getBoolean("flat_uiimplementation",false)) { viewManagers.addAll(Arrays.asList( new RCTViewManager(),new RCTTextManager(),new RCTRawTextManager(),new RCTVirtualTextManager(),new RCTTextInlineImageManager(),new RCtimageViewManager(),new RCTTextInputManager(),new RCTViewPagerManager(),new FlatARTSurfaceViewManager(),new RCTModalHostManager())); } return viewManagers; }
今天的关于ReactOS 源码分析 (二) By:ProgrammeBoy和react源码深度解析 慕课网的分享已经结束,谢谢您的关注,如果想了解更多关于.Net中的反应式编程(Reactive Programming)、8 Traits of an Experienced Programmer that every beginner programmer should know、Cg Programming/ProgrammableGraphics Pipeline、com.facebook.react.views.progressbar.ReactProgressBarViewManager的实例源码的相关知识,请在本站进行查询。
本文标签: