进程与线程
2016-01-15 14:10
141 查看
1.进程的状态
1)进程有哪几种状态?
就绪态:可运行,但因为其他进程在运行而暂时停止。
运行态:该时刻进程实际占用CPU。
阻塞态:除非某种外部事件发生,否则进程不能运行。
2)状态转换图
a.运行态转为阻塞态:进程为等待输入而阻塞。
b.阻塞态转为就绪态:出现有效输入。
c.运行态转为就绪态:调度程序选择另一个进程。
d.就绪态转为运行态:调度程序选择这个进程。
转换c和d是由进程调度程序引起的。
2.进程与线程的区别
进程:一个正在执行程序的实例,包括程序计数器、寄存器和变量的当前值。进程是系统进行资源分配的基本单位。
线程:是进程的一个实体,是CPU调度运行的基本单位,进程中执行运算的最小单元。线程自己基本上不拥有系统资源只拥有一点在运行中必不可少的资源(程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他进程共享进程所拥有的全部资源。
注意:
1)程序计数器:用来记录接着要执行哪一条指令。寄存器:用来保存线程当前的工作变量。栈:用来记录执行历史,其中每一帧保存了一个已调用的但是还没有从中返回的过程。
2)除了共享地址空间之外,所有线程还共享同一个打开文件集、子进程、报警以及相关信号等。
3)线程之间的进程转换和进程是一样的。
3.多线程的优点
1) 应用程序中往往同时发生着多种活动,其中某些活动随时间的推移会被阻塞。通过将这些应用程序分解成可以准并运行的多个顺序线程,程序设计模型会变得更加简单。
2) 线程比进程更轻量级,更容易创建和撤销。
3) 如果应用程序中存在大量的计算和I/O处理,拥有多个线程允许这些活动彼此重叠进行,从而会加快程序执行的速度。
4) 在多CPU系统中,多线程可以实现真正的并行运算。
4.什么是用户空间实现线程?其优缺点是什么?
线程在一个运行时系统的顶部运行,这个运行时系统是一个管理线程的过程的集合。
在用户空间管理线程时,每个进程需要有其专用的线程表,用来跟踪该进程中的线程。该线程表仅仅记录各个线程的属性,入每个线程的程序计数器、堆栈指针和状态等。
当一个线程转换到就绪状态或阻塞状态时,在该线程表中存放重新启动该线程所需的信息,与内核在进程表中存放进程的信息完全一样。
优点:
(1) 用户级线程包可以在不支持线程的操作系统上实现。
(2) 线程切换至少要比陷入内核要快一个数量级。在线程完成运行时,它调用thread_yield可以把该线程的信息保存在线程表中;进而,它可以调用线程调度程序来选择另一个要运行的线程。保存该线程状态的过程和调度程序都只是本地过程,所以启动它们比进行内核调用效率更高。另一方面,不需要陷阱,不需要上下文切换,也不需要对内存高速缓存进行刷新,这使得线程调度非常快捷。
(3) 允许每个进程有自己定制的调度算法。
(4) 具有较好的可扩展性,这是因为在内核空间中内核线程需要一些固定表格空间和堆栈空间,当内核线程的数量非常大,就会出现问题。
缺点:
(1) 如何实现阻塞系统调用而不影响其它线程。一种方法是使用非阻塞版本的系统调用;另一种方法是使用包装器(jacket 或 wrapper),在进行阻塞系统调用之前检查是否会引起阻塞,如果调用会被阻塞,有关的调用就不进行,代之以运行另一个线程。
(2) 在一个单独的进程内部,没有时钟中断,所以不能用轮转调度的方式调度线程。如果一个线程开始运行,那么在该进程中的其他线程就不能运行,除非第一个线程自动放弃CPU。
5.什么是在内核中实现线程?
此时不需要运行时系统了,另外每个进程中也没有线程表。相反,在内核中有用来记录系统中所有线程的线程表。
当一个线程阻塞时,内核可以根据其选择,可以运行同一个进程中的另一个线程,或者运行另一个进程中的线程。而在用户级线程中,运行时系统始终运行自己进程中的线程,直到内核剥夺它的CPU为止。
内核级线程的缺点是:应用程序线程在用户态运行,而线程调度和管理在内核实现。在同一进程中,控制权从一个线程转移到另一个线程,需要用户态-内核态-用户态的模式切换,系统开销较大。
综上:用户级线程和内核级线程之间的差别在于性能。用户级线程的切换需要少量的机器指令,而内核级线程需要完整的上下文切换,修改内存映像,使高速缓存失效,这导致了若干数量级的延迟。另一方面,在使用内核级线程时,一旦线程阻塞在I/O就不需要像在用户级线程中那样将整个进程挂起。
6.进程间通信的几种方式
管道:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
有名管道:克服了管道没有名字的限制,因此允许无亲缘关系进程间通信。
信号量: 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
消息队列: 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
信号: 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
共享内存:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
套接字: 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
7.线程同步的几种方式
临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。(对共享内存进行访问的程序片段称作临界区。)
事件:为协调共同对一个共享资源的单独访问而设计的。
互斥量:为控制一个具有有限数量用户资源而设计。
信号量:用来通知线程有一些事件已发生,从而启动后继任务的开始。
8.什么是临界区?如何避免竞争条件?
每个进程中访问临界资源的那段程序称为临界区,每次只准许一个进程进入临界区,进入后不允许其他进程进入。
(1)如果有若干进程要求进入空闲的临界区,一次仅允许一个进程进入;
(2)任何时候,处于临界区内的进程不可多于一个。如已有进程进入自己的临界区,则其它所有试图进入临界区的进程必须等待;
(3)进入临界区的进程要在有限时间内退出,以便其它进程能及时进入自己的临界区;
(4)如果进程不能进入自己的临界区,则应让出CPU,避免进程出现“忙等”现象。
9.实现互斥的几种方案
1)屏蔽中断:使每个进程在刚进入临界区后立即屏蔽所有中断,并在就要离开之前再打开中断。(CPU只有发生时钟中断或其他中断时才会进行进程切换。)
2)锁变量:有一个共享锁变量,初始值为0。当一个进程想进入临界区时,首先测试锁变量,如果值为0,则将该值设为1,并进入临界区。否则,等待直到锁变量变为0才进入。
3)严格轮换法:
整型变量turn,初始值为0,用于记录轮到哪个进程进入临界区,并检查或更新共享内存。开始时,进程0检查turn,发现其值为0,于是进入临界区。进程1也发现其值为0,所以在一个等待循环中不停地测试turn,看其值何时变为1。连续测试一个变量直到某个值出现为止,称为忙等待。
只有在有理由认为等待时间非常短的情形下,才使用忙等待。用于忙等待的锁,称为自旋锁。
4)Peterson解法
5)TSL指令
10.关于调度的几点认识
1)进程行为
计算密集型进程:进程花费绝大多数时间在计算上。
I/O密集型进程:进程在I/O等待上花费绝大多数时间。
2)何时调度
第一,在创建一个新进程后,需要决定是运行父进程还是运行子进程。
第二,在一个进程退出时必须做出调度决策。(从就绪进程集中选择另外某个进程,如果没有就绪进程,通常会运行一个系统提供的空闲进程。)
第三,当一个进程阻塞在I/O和信号量上或其他原因阻塞时,必须选择另外一个进程运行。
第四,当一个I/O中断发生时,必须做出调度决策。
3)调度算法分类
不同的环境需要不同的调度算法,有下面三种环境:
a.批处理:用户将一批作业提交给操作系统后就不再干预,由操作系统控制它们自动运行。非抢占算法或对每个进程都有长时间周期的抢占算法,通常都可以接受。
b.交互式:为了避免一个进程霸占CPU拒绝为其它进程服务,抢占是必须的。
c.实时:时间起主导作用的系统。外部的一种或多种物理设备给了计算机一个刺激,而计算机必须在一个确定的时间范围内恰当地做出反应。
4)不同系统的指标
a.所有系统
公平:给每个进程公平的CPU份额
策略强制执行:看到所宣布的策略执行
平衡:保持系统的所有部分都忙碌
b.批处理系统
吞吐量:系统每小时完成的作业数量。
周转时间:一个批处理作业从提交到终止间的平均时间。
CPU利用率:常常用于对批处理系统的度量。
c.交互式系统
最小响应时间:从发出命令到得到响应之间的时间。
均衡性:满足用户的期望。
d.实时系统
满足截止时间:避免丢失数据。
可预测性:在多媒体系统中避免品质降低。
11.批处理系统中的调度
1)先来先服务:非抢占式,进程按照他们请求CPU的顺序使用CPU。
2)最短作业优先:非抢占式,在所有的作业都可同时运行的情形下,最短作业优先算法是最优的。
3)最短剩余时间优先:如果新的进程比当前运行进程需要更短的时间,当前进程就被挂起,而运行新的进程。
12.交互式系统中的调度
1)轮转调度:每个进程被分配一个时间段,称为时间片,即允许该进程在该时间段中运行。如果在时间片结束时该进程还在运行,则将剥夺CPU并分配给另一个进程。如果该进程在时间片结束前阻塞或结束,则CPU立即进行切换。(时间片设得太短会导致过多的进程切换,降低了CPU效率;而设得太长又可能引起对短的交互请求的响应时间变长。20ms到50ms比较合理。)
2)优先级调度:每个进程被赋予一个优先级,允许优先级最高的可运行进程先运行。
3)多级队列
4)最短进程优先:交互进程遵循模式为等待命令、执行命令、等待命令、执行命令,如此不断反复。如果将每一条命令的执行看作是一个独立的“作业”,则可以首先运行最短的作业来使响应时间最短。
5)保证调度:n个进程,则每个进程获得1/n的CPU时间。然后计算各个进程自创建以来的时间除以n。很容易计算出真正获得的CPU时间和应获得的CPU时间之比。该算法转向比率最低的进程,直到该进程的比率超过它的最接近竞争者为止。
6)彩票调度:向进程提供各种系统资源彩票,一旦需要作出一项调度决策时,就随机抽出一张彩票,拥有该彩票的进程获得资源。
7)公平分享调度:每个用户分配到CPU时间的一部分,而调度程序以一种强制的方式选择进程。这样无论一个用户有多少进程存在,每个用户获得相同CPU时间。
13.线程调度
1)对于用户级线程,内核不知道线程存在。内核还是和以前一样操作,选择进程A,并给于时间片。A中的线程调度程序决定那个线程运行,加上A1。由于多线程并不存在时钟中断,所以这个线程可以按其意愿任意运行多长时间。如果该线程用完了进程的全部时间片,内核就会选择另一个进程运行。
2)对于内核级线程,内核选择一个线程运行,不考虑该线程属于哪个进程。对被选择的线程赋予一个时间片,如果超过了时间片,就会强制挂起该线程。
用户级线程和内核级线程之间的差别在于性能。用户级线程的线程切换需要少量的机器指令,而内核级线程需要完整的上下文切换,修改内存映像,使高速缓存失效,导致了若干数量级的延迟。另一方面,在使用内核级线程时,一旦线程阻塞在I/O上就不需要像在用户级线程中那样将整个进程挂起。
1)进程有哪几种状态?
就绪态:可运行,但因为其他进程在运行而暂时停止。
运行态:该时刻进程实际占用CPU。
阻塞态:除非某种外部事件发生,否则进程不能运行。
2)状态转换图
a.运行态转为阻塞态:进程为等待输入而阻塞。
b.阻塞态转为就绪态:出现有效输入。
c.运行态转为就绪态:调度程序选择另一个进程。
d.就绪态转为运行态:调度程序选择这个进程。
转换c和d是由进程调度程序引起的。
2.进程与线程的区别
进程:一个正在执行程序的实例,包括程序计数器、寄存器和变量的当前值。进程是系统进行资源分配的基本单位。
线程:是进程的一个实体,是CPU调度运行的基本单位,进程中执行运算的最小单元。线程自己基本上不拥有系统资源只拥有一点在运行中必不可少的资源(程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他进程共享进程所拥有的全部资源。
注意:
1)程序计数器:用来记录接着要执行哪一条指令。寄存器:用来保存线程当前的工作变量。栈:用来记录执行历史,其中每一帧保存了一个已调用的但是还没有从中返回的过程。
2)除了共享地址空间之外,所有线程还共享同一个打开文件集、子进程、报警以及相关信号等。
3)线程之间的进程转换和进程是一样的。
3.多线程的优点
1) 应用程序中往往同时发生着多种活动,其中某些活动随时间的推移会被阻塞。通过将这些应用程序分解成可以准并运行的多个顺序线程,程序设计模型会变得更加简单。
2) 线程比进程更轻量级,更容易创建和撤销。
3) 如果应用程序中存在大量的计算和I/O处理,拥有多个线程允许这些活动彼此重叠进行,从而会加快程序执行的速度。
4) 在多CPU系统中,多线程可以实现真正的并行运算。
4.什么是用户空间实现线程?其优缺点是什么?
线程在一个运行时系统的顶部运行,这个运行时系统是一个管理线程的过程的集合。
在用户空间管理线程时,每个进程需要有其专用的线程表,用来跟踪该进程中的线程。该线程表仅仅记录各个线程的属性,入每个线程的程序计数器、堆栈指针和状态等。
当一个线程转换到就绪状态或阻塞状态时,在该线程表中存放重新启动该线程所需的信息,与内核在进程表中存放进程的信息完全一样。
优点:
(1) 用户级线程包可以在不支持线程的操作系统上实现。
(2) 线程切换至少要比陷入内核要快一个数量级。在线程完成运行时,它调用thread_yield可以把该线程的信息保存在线程表中;进而,它可以调用线程调度程序来选择另一个要运行的线程。保存该线程状态的过程和调度程序都只是本地过程,所以启动它们比进行内核调用效率更高。另一方面,不需要陷阱,不需要上下文切换,也不需要对内存高速缓存进行刷新,这使得线程调度非常快捷。
(3) 允许每个进程有自己定制的调度算法。
(4) 具有较好的可扩展性,这是因为在内核空间中内核线程需要一些固定表格空间和堆栈空间,当内核线程的数量非常大,就会出现问题。
缺点:
(1) 如何实现阻塞系统调用而不影响其它线程。一种方法是使用非阻塞版本的系统调用;另一种方法是使用包装器(jacket 或 wrapper),在进行阻塞系统调用之前检查是否会引起阻塞,如果调用会被阻塞,有关的调用就不进行,代之以运行另一个线程。
(2) 在一个单独的进程内部,没有时钟中断,所以不能用轮转调度的方式调度线程。如果一个线程开始运行,那么在该进程中的其他线程就不能运行,除非第一个线程自动放弃CPU。
5.什么是在内核中实现线程?
此时不需要运行时系统了,另外每个进程中也没有线程表。相反,在内核中有用来记录系统中所有线程的线程表。
当一个线程阻塞时,内核可以根据其选择,可以运行同一个进程中的另一个线程,或者运行另一个进程中的线程。而在用户级线程中,运行时系统始终运行自己进程中的线程,直到内核剥夺它的CPU为止。
内核级线程的缺点是:应用程序线程在用户态运行,而线程调度和管理在内核实现。在同一进程中,控制权从一个线程转移到另一个线程,需要用户态-内核态-用户态的模式切换,系统开销较大。
综上:用户级线程和内核级线程之间的差别在于性能。用户级线程的切换需要少量的机器指令,而内核级线程需要完整的上下文切换,修改内存映像,使高速缓存失效,这导致了若干数量级的延迟。另一方面,在使用内核级线程时,一旦线程阻塞在I/O就不需要像在用户级线程中那样将整个进程挂起。
6.进程间通信的几种方式
管道:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
有名管道:克服了管道没有名字的限制,因此允许无亲缘关系进程间通信。
信号量: 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
消息队列: 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
信号: 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
共享内存:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
套接字: 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
7.线程同步的几种方式
临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。(对共享内存进行访问的程序片段称作临界区。)
事件:为协调共同对一个共享资源的单独访问而设计的。
互斥量:为控制一个具有有限数量用户资源而设计。
信号量:用来通知线程有一些事件已发生,从而启动后继任务的开始。
8.什么是临界区?如何避免竞争条件?
每个进程中访问临界资源的那段程序称为临界区,每次只准许一个进程进入临界区,进入后不允许其他进程进入。
(1)如果有若干进程要求进入空闲的临界区,一次仅允许一个进程进入;
(2)任何时候,处于临界区内的进程不可多于一个。如已有进程进入自己的临界区,则其它所有试图进入临界区的进程必须等待;
(3)进入临界区的进程要在有限时间内退出,以便其它进程能及时进入自己的临界区;
(4)如果进程不能进入自己的临界区,则应让出CPU,避免进程出现“忙等”现象。
9.实现互斥的几种方案
1)屏蔽中断:使每个进程在刚进入临界区后立即屏蔽所有中断,并在就要离开之前再打开中断。(CPU只有发生时钟中断或其他中断时才会进行进程切换。)
2)锁变量:有一个共享锁变量,初始值为0。当一个进程想进入临界区时,首先测试锁变量,如果值为0,则将该值设为1,并进入临界区。否则,等待直到锁变量变为0才进入。
3)严格轮换法:
整型变量turn,初始值为0,用于记录轮到哪个进程进入临界区,并检查或更新共享内存。开始时,进程0检查turn,发现其值为0,于是进入临界区。进程1也发现其值为0,所以在一个等待循环中不停地测试turn,看其值何时变为1。连续测试一个变量直到某个值出现为止,称为忙等待。
只有在有理由认为等待时间非常短的情形下,才使用忙等待。用于忙等待的锁,称为自旋锁。
4)Peterson解法
5)TSL指令
10.关于调度的几点认识
1)进程行为
计算密集型进程:进程花费绝大多数时间在计算上。
I/O密集型进程:进程在I/O等待上花费绝大多数时间。
2)何时调度
第一,在创建一个新进程后,需要决定是运行父进程还是运行子进程。
第二,在一个进程退出时必须做出调度决策。(从就绪进程集中选择另外某个进程,如果没有就绪进程,通常会运行一个系统提供的空闲进程。)
第三,当一个进程阻塞在I/O和信号量上或其他原因阻塞时,必须选择另外一个进程运行。
第四,当一个I/O中断发生时,必须做出调度决策。
3)调度算法分类
不同的环境需要不同的调度算法,有下面三种环境:
a.批处理:用户将一批作业提交给操作系统后就不再干预,由操作系统控制它们自动运行。非抢占算法或对每个进程都有长时间周期的抢占算法,通常都可以接受。
b.交互式:为了避免一个进程霸占CPU拒绝为其它进程服务,抢占是必须的。
c.实时:时间起主导作用的系统。外部的一种或多种物理设备给了计算机一个刺激,而计算机必须在一个确定的时间范围内恰当地做出反应。
4)不同系统的指标
a.所有系统
公平:给每个进程公平的CPU份额
策略强制执行:看到所宣布的策略执行
平衡:保持系统的所有部分都忙碌
b.批处理系统
吞吐量:系统每小时完成的作业数量。
周转时间:一个批处理作业从提交到终止间的平均时间。
CPU利用率:常常用于对批处理系统的度量。
c.交互式系统
最小响应时间:从发出命令到得到响应之间的时间。
均衡性:满足用户的期望。
d.实时系统
满足截止时间:避免丢失数据。
可预测性:在多媒体系统中避免品质降低。
11.批处理系统中的调度
1)先来先服务:非抢占式,进程按照他们请求CPU的顺序使用CPU。
2)最短作业优先:非抢占式,在所有的作业都可同时运行的情形下,最短作业优先算法是最优的。
3)最短剩余时间优先:如果新的进程比当前运行进程需要更短的时间,当前进程就被挂起,而运行新的进程。
12.交互式系统中的调度
1)轮转调度:每个进程被分配一个时间段,称为时间片,即允许该进程在该时间段中运行。如果在时间片结束时该进程还在运行,则将剥夺CPU并分配给另一个进程。如果该进程在时间片结束前阻塞或结束,则CPU立即进行切换。(时间片设得太短会导致过多的进程切换,降低了CPU效率;而设得太长又可能引起对短的交互请求的响应时间变长。20ms到50ms比较合理。)
2)优先级调度:每个进程被赋予一个优先级,允许优先级最高的可运行进程先运行。
3)多级队列
4)最短进程优先:交互进程遵循模式为等待命令、执行命令、等待命令、执行命令,如此不断反复。如果将每一条命令的执行看作是一个独立的“作业”,则可以首先运行最短的作业来使响应时间最短。
5)保证调度:n个进程,则每个进程获得1/n的CPU时间。然后计算各个进程自创建以来的时间除以n。很容易计算出真正获得的CPU时间和应获得的CPU时间之比。该算法转向比率最低的进程,直到该进程的比率超过它的最接近竞争者为止。
6)彩票调度:向进程提供各种系统资源彩票,一旦需要作出一项调度决策时,就随机抽出一张彩票,拥有该彩票的进程获得资源。
7)公平分享调度:每个用户分配到CPU时间的一部分,而调度程序以一种强制的方式选择进程。这样无论一个用户有多少进程存在,每个用户获得相同CPU时间。
13.线程调度
1)对于用户级线程,内核不知道线程存在。内核还是和以前一样操作,选择进程A,并给于时间片。A中的线程调度程序决定那个线程运行,加上A1。由于多线程并不存在时钟中断,所以这个线程可以按其意愿任意运行多长时间。如果该线程用完了进程的全部时间片,内核就会选择另一个进程运行。
2)对于内核级线程,内核选择一个线程运行,不考虑该线程属于哪个进程。对被选择的线程赋予一个时间片,如果超过了时间片,就会强制挂起该线程。
用户级线程和内核级线程之间的差别在于性能。用户级线程的线程切换需要少量的机器指令,而内核级线程需要完整的上下文切换,修改内存映像,使高速缓存失效,导致了若干数量级的延迟。另一方面,在使用内核级线程时,一旦线程阻塞在I/O上就不需要像在用户级线程中那样将整个进程挂起。
相关文章推荐
- matlab的输入和输出
- .net三步配置错误页面,让你的站点远离不和谐的页面
- OJ 系列之字符串基本操作
- EasyUi combotree 使用总结
- kilo版openstack的dashboard在session超时后重新登录报错解决办法
- iOS 控件——UILable多文本垂直方向对齐的设置
- Dreamweaver_CS6安装与破解,手把手教程
- 第一个iOS程序:Hello iOS
- Protobuf的那些事
- Android退出应用最优雅的方式
- sql 2008 R2添加对MySql的远程服务器链接
- 从框架到完整项目搭建,实战项目《约个球》(1)-从splashActivity说起
- iOS 支付宝支付
- Tomcat中JVM内存溢出及合理配置
- 选择列表控件的使用(PickList)
- 最简单安装svn插件方法
- haproxy后端nginx取得用户访问ip地址
- DataStructures:algorithm analysis
- 无法删除Java(TM) Platform SE binary打开问题解决(修改jar中的文件)
- android上传图片到服务器(使用base64字节流的形式通过 AsyncHttpClient框架传输)