Linux信号
- 信号本质上就是一个软件中断,它既可以作为两个进程间的通信的方式, 更重要的是, 信号可以终止一个正常程序的执行, 通常被用于处理意外情况 ,* 信号是异步的, 也就是进程并不知道信号何时会到达
- $kill -9 3390 #向PID为3390的进程发送编号为9的信号=>一个两个进程间通信的方式之一
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
- 一共62个,不是64个, 历史原因, 没有32,33
- 1~31之间的信号叫做不可靠信号, 不支持排队, 信号可能会丢失, 也叫做非实时信号
- 34~64之间的信号叫做可靠信号, 支持排队, 信号不会丢失, 也叫做实时信号
绝大多数信号的默认处理方式都是终止进程, 另外两种默认处理方式: 忽略处理, 自定义处理
| 1) | SIGHUP | 连接挂断 | 终止(默认处理) |
| 2) | SIGINT | 终端中断,Ctrl+c产生该信号 | 终止(terminate) |
| 3) | SIGQUIT | 终端退出,Ctrl+\ | 终止+转储 |
| 4) | SIGILL | *进程试图执行非法指令 | 终止+转储 |
| 5) | SIGTRAP | 进入断点 | 终止+转储 |
| 6) | SIGABRT | *进程异常终止,abort()产生 | 终止+转储 |
| 7) | SIGBUS | 硬件或对齐错误 | 终止+转储 |
| 8) | SIGFPE | *浮点运算异常 | 终止+转储 |
| 9) | SIGKILL | 不可以被捕获或忽略的终止信号 | 终止 |
| 10) | SIGUSR1 | 用户定义信号1 | 终止 |
| 11) | SIGSEGV | *无效的内存段访问=>Segmentation error | 终止+转储 |
| 12) | SIGUSR2 | 用户定义信号2 | 终止 |
| 13) | SIGPIPE | 向读端已关闭的管道写入 | 终止 |
| 14) | SIGALRM | 真实定时器到期,alarm()产生 | 终止 |
| 15) | SIGTERM | 可以被捕获或忽略的终止信号 | 终止 |
| 16) | SIGSTKFLT | 协处理器栈错误 | 终止 |
| 17) | SIGCHLD | 子进程已经停止, 对于管理子进程很有用 | 忽略 |
| 18) | SIGCONT | 继续执行暂停进程(用户一般不用) | 忽略 |
| 19) | SIGSTOP | 不能被捕获或忽略的停止信号 | 停止(stop) |
| 20) | SIGTSTP | 终端挂起,用户产生停止符(Ctrl+Z) | 停止 |
| 21) | SIGTTIN | 后台进程读控制终端 | 停止 |
| 22) | SIGTTOU | 后台进程写控制终端 | 停止 |
| 23) | SIGURG | 紧急I/O未处理 | 忽略 |
| 24) | SIGXCPU | 进程资源超限 | 终止+转储 |
| 25) | SIGXFSZ | 文件资源超限 | 终止+转储 |
| 26) | SIGVTALRM | 虚拟定时器到期 | 终止 |
| 27) | SIGPROF | 实用定时器到期 | 终止 |
| 28) | SIGWINCH | 控制终端窗口大小改变 | 忽略 |
| 29) | SIGIO | 异步I/O事件 | 终止 |
| 30) | SIGPWR | 断电 | 终止 |
| 31) | SIGSYS | 进程试图执行无效系统调用 | 终止+转储 |
*系统对信号响应应视具体情况而定
发送信号的主要方式:
- 键盘 //只能发送部分特殊的信号 eg:Ctrl+C可以发送SIGINT
- 程序出错 //只能发送部分特殊的信号 eg: 出现段错误, 可以发送SIGSEGV
- $kill -Signal PID #能发所有信号
- 系统函数kill()/raise()/alarm()/sigqueue()
模型

kill()
//给任何进程或进程组发任何信号,成功返回0,失败返回-1设errno
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
pid
- pid>0 //指定pid
- pid=0 //GID是调用进程PID的子进程
- pid=-1 //任何子进程
- pid<-1 //GID是PID的子进程
sig
- sig == 0 //不发任何信号,但错误检查还是会做,可以检查PID是否存在
#include<sys/types.h>
#include<signal.h>
void fa(int signo){
printf("catch signal number:%d\n",signo);
}
int main(){
pid_t pid=fork();
if(0==pid){
…
while(1);
}
if(0==kill(pid,0)){ //if child exists
printf("parent starts to raise signal\n");
if(-1==kill(pid,40)) //if fail to kill child
perror("kill"),exit(-1);
}
return 0;
}.
raise()
//给调用的线程或进程发信号,如果发送的信号被handler处理了,会在handler返回后再返回,成功返回0,失败返回非0
#include<signal.h>
int raise(int sig);
- 在单线程程序中等价于 kill(getpid,sig)
- 在多线程程序中等价于pthread_kill(pthread_self(), sig);
if(0!=raise(SIGINT))
perror("raise success"),exit(-1);
//raise.c
#include<unistd.h>
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
void fa(int signo){
printf("catch %d success\n",signo);
}
int main(){
//设置对SIGINT自定义处理
if(SIG_ERR==signal(SIGINT,fa))
perror("signal"),exit(-1);
//5s后使用raise发送SIGINT
unsigned int second=sleep(5);
if(0==second)
printf("sleep well");
else
printf("sleep is interrupted, there are %ds left\n",second);
if(0!=raise(SIGINT))
perror("raise success"),exit(-1);
return 0;
}
alarm()
//seconds秒之后给调用进程发送SOGALRM信号,返回距离下次闹钟响起剩余的描述,没有闹钟返回0
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
seconds=0表示不设置新的SIGALRM的同时取消之前的闹钟==>专门用来取消闹钟
//alarm.c
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
void fa(int signo){
printf("catch %d\n",signo);
alarm(1);
}
int main(){
// 设置对信号SIGALRM进行自定义处理;
if(SIG_ERR==signal(SIGALRM,fa))
perror("signal"),exit(-1);
// 设置5s发送SIGALRM;
unsigned int second=alarm(5);
printf("second=%u\n",second); //0
sleep(2);
//调整闹钟10s后响(发SIGALRM),second是3
second=alarm(10);
printf("second=%u\n",second); //3
//取消闹钟(不会发SIGALRM),second是3
// second=alarm(0);
// printf("second=%d\n",second); //10
while(1);
return 0;
}
sigqueue()
//将信号和数据排好发给指定进程,成功返回0,失败返回-1设errno
#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);
pid //进程的编号(给谁发信号)
sig //信号值/信号的名称(发送什么样的信号)
value //联合类型的附加数据(伴随什么样的数据)
union sigval {
int sival_int;
void *sival_ptr;
};
void fa(int signo,siginfo_t* info,void* pv){
printf("进程%d发来的信号是:%d,附加数据是%d\n",info->si_pid,signo,info->si_value);
}
int main(){
//设置对信号40的自定义处理
struct sigaction action={};
action.sa_sigaction=fa;
action.sa_flags=SA_SIGINFO;
int res=sigaction(40,&action,NULL);
if(-1==res)
perror("sigaction"),exit(-1);
pid_t pid=fork();
if(-1==pid)
perror("fork"),exit(-1);
if(0==pid){ //child开始, 发送1~100之间的数据发给parent
printf("child%dstarts\n",getpid());
int i=1;
for(i=1;i<=100;i++){
union sigval value;
value.sival_int=i;
sigqueue(getppid(),40,value);//这里没有错误处理
}
exit(0);
}
while(1);
return 0;
}
sleep()
//让调用的线程睡seconds秒,除非这期间收到了不能忽略的信号,成功返回0,失败返回剩余没睡的时间
#include <unistd.h>
unsigned int sleep(unsigned int seconds);
unsigned int second=sleep(5);
if(0==second)
printf("sleep well");
else
printf("sleep is interrupted, there are %ds left\n",second);
pause()
//让调用的线程一直睡直到接收到了一个终止进程或者引发捕获信号函数的信号,当接受到这样的信号时,返回-1设errno
int pause(void);
void ding(int signo){
}
int main(){
(void) signal(SIGALRM, ding); //ding是一个函数
pause();
}
Q:pause 放在signal-catching很远的地方可以吗
A:pause就相当于sleep(∞), 跟捕捉语句没什么关系,谁说一定要组合用的
Q: 写了捕获语句, 是不是就使整个进程有了捕获某个信号的能力还是只是这一句???
A:当然不是, signal就像是全局变量, 使用sigaction()对某个信号进行重定向后, 此后的程序遇到这个信号就使用新的处理方式
signal()
//重新设置对信号的处理方式,将信号signum交给handler处理,成功返回之前的signal handler,失败返回-1设errno
#include <signal.h>
sighandler_t signal(int signum, sighandler_t handler);
handler
- SIG_IGN(Signal ignore)
- SIG_DFL(Signal default)
- User-defined fhandler with argument signum
#include<signal.h>
void fa(int signo){
printf("catch signal:%d\n",signo);
if(SIG_ERR==signal(signo,SIG_DFL))
perror("signal"),exit(-1);
}
int main(){
if(SIG_ERR==signal(3,fa))
perror("signal"),exit(-1);
return 0;
}
信号集
信号的集合,当前系统所支持的信号范围:164(共62个),就是说每个进程可以使用信号164,为了对信号操作方便, 我们把一些信号放在一个集合中一起处理, 很多函数(包括sigpromask,sigpending)都是对信号集操作而不是对单个信号
sigset_t
Linux中表示信号集的数据类型, 就是一个超级大的整数(128byte, 32个unsigned long int的数组), 底层采用一个二进制位来代表一个信号, 根据该二进制位为0 or 1表示该信号是否存在
typedef struct{
unsigned long int __val[(1024 / (8 * sizeof (unsigned long int)))];
}__sigset_t;
typedef __sigset_t sigset_t;
在当前系统中, 按照%d打印的话就是打印信号集类型中的低4个字节的数据其实当前只需要8byte, 设计这么大是为了未来扩展
sigemptyset() /sigfillset()/sigaddset()/sigdelset()/sigismember()
//这些都是信号集操作函数
//sigemptyset()/sigfillset()/ sigaddset()/ sigdelset() 成功返回0,失败返回-1设errno
//如果signum是指定信号集的一员,sigismember()返回1,不是返回0,失败返回-1设errno。
#include <signal.h>
int sigemptyset(sigset_t *set); //清空信号集
int sigfillset(sigset_t *set); //填满信号集
int sigaddset(sigset_t *set, int signum); //添加信号到信号集
int sigdelset(sigset_t *set, int signum); //删除信号集的信号
int sigismember(const sigset_t *set, int signum); //判断信号是否属于信号集
sigprocmask()
//sigprocmask()只适用与单线程进程,多线程的参考pthread_sigmask()
//在某些特殊程序的执行过程中, 是不能被信号打断的, 此时需要信号的屏蔽技术来解决该问题
//获取并修改调用线程的屏蔽信号集
//成功返回0,失败返回-1设errno
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
how
- SIG_BLOCK //新的屏蔽信号集是原有集合(不是oldset,oldset是用来存储的)和set的合集
- SIG_UNBLOCK //set内的信号被从屏蔽集合oldset中移除
- SIG_SETMASK //屏蔽信号集就是setThe set of blocked signals is set to the argument set.
oldset
- 如果oldset 不是NULL,则之前的信号集被存储在其中
- 如果set是NULL,屏蔽信号集不会变量,但现存的屏蔽信号集还是会被存储在oldset中
//准备信号集中有:2,3
sigset_t set,oldset;
if(-1==sigemptyset(&set))
perror("sigemptyset"),exit(-1);
if(-1==sigemptyset(&oldset))
perror("sigemptyset"),exit(-1);
if(-1==sigaddset(&set,2))
perror("sigaddset"),exit(-1);
//设置屏蔽的信号集
if(-1== sigprocmask(SIG_SETMASK,&set,&oldset))
perror("sigprocmask"),exit(-1);
- 信号屏蔽并不是删除信号, 而是将信号单独保存起来, 等信号的屏蔽解除之后, 信号还是会被处理的
- 可靠信号: 支持排队, mask期间有多少信号, mask解除之后就会处理多少
- 不可靠信号:不支持排队, mask期间有多个信号时, mask解除之后只处理第一个
sigpending()
//检查mask期间捕捉到但是没有处理的信号, 通过形参带出结果,成功返回0,失败返回-1设errno
#include <signal.h>
int sigpending(sigset_t *set);
sigaction()
//是前面的信号处理的集大成者且有很多扩展,是一个非常健壮的signal处理接口,建议使用,成功返回0,失败返回-1设errno
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
signum可以代表除了SIGSTOP和SIGKILL之外的任何一个信号
如果NULL!=act,act作为针对signal的新的action。
如果NULL!=oldact, 之前的action被存储在oldact。
act/oldact:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void); //obsolete, should not be used.
};
如果 sa_flags 被设为SA_SIGINFO,则sa_sigaction用来作signum的handler, 否则,用sa_handler。
sa_handler表明针对signum的handler,和signal()第二个参数类型一致, 都是用于设置signal信号的处理方式SIG_DFL,SIG_IGN,user-defined handler
//sa_sigaction
struct siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; /*Trap number that caused hardware-generated signal
pid_t si_pid; /* Sending process ID */ //发送信号的进程号
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */ //伴随信号到来的附加数据
int si_int; /* POSIX.1b signal */
void* si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count; POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void* si_addr; /* Memory location which caused fault */
long si_band; /* Band event (was int in glibc 2.3.2 and earlier) */
int si_fd; /* File descriptor */
short si_addr_lsb; /* Least significant bit of address(since kernel 2.6.32) */
}
sa_mask 表明在信号handler执行期间需要屏蔽的信号,此外,出发handler的信号默认是被屏蔽的,除非flag里指定的SA_NODEFE
sa_flags(Bitwise Or)
- SA_NOCLDSTOP //If signum is SIGCHLD, do not receive notification when child processes stop (i.e., when they receive one of SIGSTOP, SIGTSTP, SIGTTIN or SIGTTOU) or resume (i.e., they receive SIGCONT) (see wait(2)). This flag is only meaningful when establishing a handler for SIGCHLD.
- SA_NOCLDWAIT //If signum is SIGCHLD, do not transform children into zombies when they terminate. See also waitpid(2). This flag is only meaningful when establishing a handler for SIGCHLD, or when setting that signal's disposition to SIG_DFL.If the SA_NOCLDWAIT flag is set when establishing a handler for SIGCHLD, POSIX.1 leaves it unspecified whether a SIGCHLD signal is generated when a child process terminates. On Linux, a SIGCHLD signal is generated in this case; on some other implementations, it is not.
- SA_NODEFER //解除对触发信号处理函数相同信号的屏蔽
- SA_ONSTACK //Call the signal handler on an alternate signal stack provided by sigaltstack(2). If an alternate stack is not available, the default stack will be used. This flag is only meaningful when establishing a signal handler.
- SA_RESETHAND //一旦信号处理函数被调用之后, 信号的处理方式就会恢复为默认处理方式
- SA_RESTART //Provide behavior compatible with BSD signal semantics by making certain system calls restartable across signals.This flag is only meaningful when establishing a signal handler. See signal(7) for a discussion of system call restarting.
- SA_SIGINFO //使用第二个函数指针设置信号的处理方式
//sigaction.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<sys/types.h>
void fa(int signo){
printf("fa1...\n");
sleep(3);
printf("fa2...\n");
}
int main(){
printf("current pid:%d\n",getpid());
//prepare struc var
struct sigaction action={};
action.sa_handler=fa;
sigemptyset(&action.sa_mask);
sigaddset(&action.sa_mask,3);
action.sa_flags=SA_NODEFER; //解除对信号2的屏蔽,sigaction(2....)
int res=sigaction(2,&action,NULL);
if(-1==res)
perror("sigaction"),exit(-1);
printf("set signal successfully\n");
while(1);
return 0;
}
sigaction()那点事:
- 使用sigaction(),需要明确两个act,一个用来存储老act的oldact,一个用来安装新act的act,
- 这两个act都是struct sigaction
- 结构体有两个函数分别指明对sig的处理方式,具体使用哪个需要看flag是否被set了SA_SIGINFO,set了,就是sa_sigaction()处理信号,没set,就是sa_handler,前者比后者的功能更多,后者其实就是signal()
- 指明了用哪个函数处理了信号,我们还可以指定在signal handler执行的过程中哪些SIG被mask,注意这个是sigset_t类型,把要mask的信号放在一个信号集里,默认条件下the signal which triggered the handler是被mask的,除非在sa_flags中set了SA_NODEFER;
- 可以看到,整个act中flags主要起到了配置的作用,它决定使用哪个handler(SA_SIGINFO),也决定要不要屏蔽触发信号(SA_NODEFER);
- 除了这两个,flags还有其他选项
void fa(int signo,siginfo_t* info,void* pv){
printf("进程%d发来了信号%d\n",info->si_pid,signo);
}
int main(){
struct sigaction action={};
action.sa_sigaction=fa;
action.sa_flags=SA_SIGINFO;
if(-1== sigaction(2,&action,NULL))
perror("sigaction"),exit(-1);
return 0;
}
父子进程信号
- 对于fork()创建的child, child完全照搬parent对信号的处理方式:
- parent忽略=>child忽略;
- parent默认=>child默认;
- arent自定义=>child自定义;
- 对于vfork(),execl()启动的child, 部分照搬parent的信号处理方式:
- parent忽略=>child忽略;
- parent默认=>child默认;
- parent自定义=>child默认=>因为execl()已经跳出的子进程, 而process.out里面没有fa,所以会按默认方式处理
#include<unistd.h>
#include<sys/types.h>
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
void fa(int signo){
printf("%d\n",signo);
}
int main(){
if(SIG_ERR==signal(2,fa))
perror("signal"),exit(-1);
if(SIG_ERR==signal(3,SIG_IGN))
perror("signal"),exit(-1);
pid_t pid=vfork();
if(-1==pid)
perror("vfork"),exit(-1);
if(0==pid){
printf("child's pid=%d\n",getpid());
int res=execl("process.out","process.out",NULL);
if(-1==res)
perror("execl"),exit(-1);
while(1);
}
return 0;
}
Linux信号的更多相关文章
- Linux信号类型说明
说明 在Linux系统开发中经常要使用到信号来实现异步通知机制.而在Linux系统中信号有很多种,也不用全部记住,学习几种常见的信号,学会使用即可:当然也要知道用哪种方式能够发送这样的信号. 查看li ...
- Linux信号基础
Linux信号基础 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! Linux进程基础一文中已经提到,Linux以进程为单位来 ...
- Linux信号(signal) 机制分析
Linux信号(signal) 机制分析 [摘要]本文分析了Linux内核对于信号的实现机制和应用层的相关处理.首先介绍了软中断信号的本质及信号的两种不同分类方法尤其是不可靠信号的原理.接着分析了内核 ...
- 利用linux信号机制调试段错误(Segment fault)
在实际开发过程中,大家可能会遇到段错误的问题,虽然是个老问题,但是其带来的隐患是极大的,只要出现一次,程序立即崩溃中止.如果程序运行在PC中,segment fault的调试相对比较方便,因为可以通过 ...
- Linux信号实践(2) --信号分类
信号分类 不可靠信号 Linux信号机制基本上是从UNIX系统中继承过来的.早期UNIX系统中的信号机制比较简单和原始,后来在实践中暴露出一些问题,它的主要问题是: 1.进程每次处理信号后,就将对信号 ...
- 非常好的一篇对linux信号(signal)的解析 (转载)【转】
转自:https://blog.csdn.net/return_cc/article/details/78845346 Linux信号(signal) 机制分析 转载至:https://www.cnb ...
- Linux 信号:signal 与 sigaction
0.Linux下查看支持的信号列表: france@Ubuntux64:~$ kill -l ) SIGHUP ) SIGINT ) SIGQUIT ) SIGILL ) SIGTRAP ) SIGA ...
- Linux信号机制
Linux信号(signal) 机制分析 [摘要]本文分析了Linux内核对于信号的实现机制和应用层的相关处理.首先介绍了软中断信号的本质及信号的两种不同分类方法尤其是不可靠信号的原理.接着分析了内核 ...
- python学习笔记——多进程间通信——Linux信号基础
1 信号的基本描述 Signal信号(其全程为软中断信号)是Linux系统编程中非常重要的概念,信号是异步进程中通信的一种方式. 作用是通知进程发生了异步事件.进程之间可以调用系统来传递信号, 本身内 ...
- linux信号Linux下Signal信号太详细了,终于找到了
linux信号Linux下Signal信号太详细了,终于找到了 http://www.cppblog.com/sleepwom/archive/2010/12/27/137564.html
随机推荐
- Java程序内存的简单分析
这篇文章将简单的说明下当我们运行Java程序时JVM(Java虚拟机)的内存分配情况. 首先我们先来感观的认识下几个名词: 1.栈,一般来说,基本数据类型直接在栈中分配空间,局部变量(在方法代码段中定 ...
- Linux命令详解之—less命令
Linux下还有一个与more命令非常类似的命令--less命令,相比于more命令,less命令更加灵活强大一些,今天就给大家介绍下Linux下的less命令. 更多Linux命令详情请看:Linu ...
- 软件代码生成之Codesmith模板.netTiers
.netTiers模板到2006年就诞生了, 到今天最后一次更新是12/17/2013, 支持.NET 4.5 and Visual Studio 2012 and 2013. n ...
- 网上图书商城2--Category模块
sql CREATE TABLE `t_category` ( `cid` char(32) NOT NULL, `cname` varchar(50) DEFAULT NULL, `pid` cha ...
- iCheck.js
一.iCheck:http://www.bootcss.com/p/icheck/ 1.选择一个颜色主题,网上有,有了一个肤色主题,然后就是把这个肤色主题的css文件复制到iCheck文件夹里面 2. ...
- Python的下载与安装
linux系统由于自身的需要,自带了Python,而Windows的系统就没有自带Python.本篇Blog介绍在win8.1下,安装Pathon需要注意的问题,包括常见的0x80240017.250 ...
- sublime text3 之snippet编写代码片段
sublime text 3 中有个强大的功能就是可以编写各种文件类型的snippet代码片段,可以节省大量的时间. 文件名为:jekyll-top.sublime-snippet(.sublime- ...
- 轻松掌握:JavaScript享元模式
享元模式 在JavaScript中,浏览器特别是移动端的浏览器分配的内存很有限,如何节省内存就成了一件非常有意义的事情.节省内存的一个有效方法是减少对象的数量. 享元模式(Flyweight),运行共 ...
- Sharepoint学习笔记—习题系列--70-576习题解析 -(Q1-Q3)
这里我把从网上搜集到的针对Sharepoint 70-576的有关练习进行系统的解析,整理成一个系列, 分期.分批次共享出来,供大家研究. 70-573考试注重的是"知道"相关知识 ...
- IOS开发--微信支付
前言:下面介绍微信支付的开发流程的细节,图文并茂,你可以按照我的随笔流程过一遍代码.包你也学会了微信支付.而且支付也是面试常问的内容. 正文: 1.首先在开始使用微信支付之前,有一些东西是开发者必须要 ...