一、 环境变量

    应用程序在执行的时候,可能需要获取系统的环境变量,从而执行一些相应的操作。
    在linux中有两种方法获取环境变量,分述如下。
 
1、通过main函数的参数获取环境变量
     main函数的多种定义方式:
     int main(void);
int main(int argc, char* argv[ ]);
int main(int argc, char* argv[ ], char* env[ ] )
    方式1和方式2比较常见,下面介绍一下方式3: 第三个参数获取系统的环境变量。
Exp:
#include <stdio.h>

int main(int argc,char* argv[], char* env[])
{
int i=; while(env[i])
{
puts(env[i++]);
} return ;
}

程序执行的时候就可以输出所有的环境变量。

 
2、访问全局变量 environ 获取环境变量
    在加载应用程序的时候,linux系统会为每一个应用程序复制一份系统环境变量副本,保存在全局变量 enviro 中。
可以通过这个全局的变量访问系统的环境变量。
Exp:
#include <stdio.h>

extern char** environ;

int main(int argc,char* argv[])
{
int i=; while(environ[i])
{
puts(environ[i++]);
} return ;
}

3、获取指定的环境变量

    linux提供环境变量操作相关的函数: getenv( )、putenv( )、setenv()、unsetenv()、clearenv( ).
   
getenv( )
GETENV()                  Linux Programmer’s Manual                 GETENV()
NAME
getenv - get an environment variable SYNOPSIS
#include <stdlib.h> char *getenv(const char *name); //要获取的环境变量,比方说传递的是 "HOME" ,将返回HOME的值
返回值:
        成功返回指向环境变量的值的指针,失败返回NULL。
 
putenv( )
UTENV()                  Linux Programmer’s Manual                 PUTENV()
NAME
putenv - change or add an environment variable //增加或者改变环境变量的值
SYNOPSIS
#include <stdlib.h> int putenv(char *string); //设置的环境变量字符串, string的格式如下: HOME=/home/volcanol

setenv( ) 和 unsetenv()

SETENV()                  Linux Programmer’s Manual                 SETENV()
NAME
setenv - change or add an environment variable //改变或者增加环境变量
SYNOPSIS
#include <stdlib.h> int setenv(const char *name, //要设置的环境变量名;如果不存在就会创建新的环境变量,不管 overwrite的值
const char *value, //要设置的环境变量的值
int overwrite); // 如果环境变量已经存在,当 overwrite非零则改写原值, overwrite=0 则不改变原值 int unsetenv(const char *name); //要删除的环境变量
DESCRIPTION
The setenv() function adds the variable name to the environment with the value
value, if name does not already exist. If name does exist in the environment, then
its value is changed to value if overwrite is non-zero; if overwrite is zero, then
the value of name is not changed. The unsetenv() function deletes the variable name from the environment.

注意:

       unsetenv 会将环境变量删除,包括环境变量的名和环境变量的值
 
    clearenv()清除所有的环境变量,并设置environ 的值为NULL。
CLEARENV()                                                                                              CLEARENV()
NAME
clearenv - clear the environment
SYNOPSIS
#include <stdlib.h>
int clearenv(void);
DESCRIPTION
The clearenv() function clears the environment of all name-value pairs and sets the
value of the external variable environ to NULL.

  注意这个地方:  没有 linux  program manual  的字样,表示这个函数需要慎重使用。

Exp:  getenv( )  和 setenv( )
#include <stdio.h>
#include <stdlib.h> int main(int argc,char* argv[])
{
char* env; setenv("Test-env","this is a test env", );
env=getenv("Test-env");
printf("the Test-env is: %s\n ",env); return ;
}
执行结果如下:
[root@localhost process]# gcc main.c
[root@localhost process]# ./a.out
the Test-env is: this is a test env
要点:
        这样设置的环境变量仅对当前进程有效,其他进程是无效的。
[root@localhost process]# ./a.out
the Test-env is:this is a test env
[root@localhost process]# env | grep "test"
[root@localhost process]# env | grep "env"
_=/bin/env
[root@localhost process]#
Exp: putenv()和unsetenv()
#include <stdio.h>
#include <stdlib.h> int main(int argc,char* argv[])
{
char* env; /*setenv("Test-env","this is a test env", 1);*/
/*env=getenv("Test-env")*/ putenv("test-env=this is a test env");
env=getenv("test-env");
printf("the test-env is:%s\n",env); unsetenv("test-env");
env=getenv("test-env");
printf("after unsetenv");
printf("the test-env is:%s\n",env); return ;
}
执行结果如下:
[root@localhost process]# gcc main.c
[root@localhost process]# ./a.out
the test-env is:this is a test env
after unsetenvthe test-env is:(null) //环境变量已经删除
[root@localhost process]#
    unsetenv( ) 会将环境变量名和值全部删除;
Exp:
#include <stdio.h>
#include <stdlib.h> extern char** environ; int main(int argc,char* argv[])
{
int i=;
char* env; /*setenv("Test-env","this is a test env", 1);*/
/*env=getenv("Test-env")*/ putenv("test-env=this is a test env");
env=getenv("test-env");
printf("the test-env is:%s\n",env); unsetenv("test-env");
env=getenv("test-env");
printf("after unsetenv");
printf("the test-env is:%s\n",env); while(environ[i])
{
printf("%s",environ[i++]);
}
return ;
}
执行结果如下:
[root@localhost process]# gcc main.c
[root@localhost process]# ./a.out | grep "test"
the test-env is:this is a test env
after unsetenvthe test-env is:(null)
[root@localhost process]#
二、进程控制
    进程控制包括: 创建新进程、执行新的应用程序和结束进程。
 
1、进程ID
    linux系统中,每一个进程都有一个唯一的标识符: PID, 即进程ID。
    在应用程序可以调用 getpid( )获取进程的ID;  调用 getppid()获取父进程的进程ID。
其原型如下:
GETPID()                  Linux Programmer’s Manual                 GETPID()
NAME
getpid, getppid - get process identification
SYNOPSIS
#include <sys/types.h>
#include <unistd.h> pid_t getpid(void);
pid_t getppid(void); DESCRIPTION
getpid() returns the process ID of the current process. (This is often used by
routines that generate unique temporary filenames.) getppid() returns the process ID of the parent of the current process.
Exp: 获取进程的PID和父进程的PID
#include <stdio.h>
#include <unistd.h> int main(void)
{
pid_t pid;
pid_t ppid; printf("pid=%d, ppid=%d\n", getpid(),getppid());
return ;
}
程序执行结果如下:
[root@localhost fork]# ./a.out
pid=, ppid=
[root@localhost fork]# ps aux | grep "bash"
root 0.0 0.3 pts/ Ss : : bash

可以发现父进程的 进程ID为 714,我们通过 ps 命令查看,可以知道 bash 的PID 为 714 ,因为 ./a.out 是由

bash 这个进程创建的,因此./a.out 的父进程的PID为 714。
 
2、执行其他程序
    linux下提供 一个函数族 在进程中执行其他应用程序。函数族为  exec 。其原型如下:
EXEC()                    Linux Programmer’s Manual                   EXEC()

NAME
execl, execlp, execle, execv, execvp - execute a file SYNOPSIS
#include <unistd.h> extern char **environ; int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,
..., char * const envp[]);
int execv(const char *path, char *const argv[]); //参数以数组的形式传递
int execvp(const char *file, char *const argv[]); //参数以数组的形式传递

exec函数族的函数,将指定的可执行程序加载到调用exec函数的进程空间执行。如果exec函数执行成功,

则不返回,exec函数执行失败才返回。加载后的可执行程序与调用exec函数的进程具有一样的进程ID.
    要点:
        execl() 和 execlp ()最后一个参数必须设置为 NULL, 否则就不能成功执行程序。
 
Exp:  
    测试exec()执行失败的情况
    下面的文件是生成  a.out 可执行文件 main.c
#include <stdio.h>
#include <unistd.h> int main(int argc,char* argv[])
{
pid_t pid; printf("in program %s, pid=%d\n",argv[],getpid()); execl("test","from caller",NULL); //exec从默认路径搜索 test 可执行文件,我系统中默认路径没有 test 可知文件,执行会失败
perror("execl"); return ;
}
    下面的文件是生成 test 可执行文件的 test.c
 #include <stdio.h>
#include <stdlib.h> int main(int argc,char* argv[])
{
pid_t pid; printf("argv[1]=%s, pid=%d\n",argv[],getpid()); return ;
}

执行结果如下:

[root@localhost fork]# vim main.c
[root@localhost fork]# vim test.c
[root@localhost fork]# gcc main.c
[root@localhost fork]# gcc -o test test.c
[root@localhost fork]# ./a.out
in program ./a.out, pid=
execl: Bad address //execl( ) 函数执行失败返回
Exp:  
    测试exec()执行成功的情况。
    将main.c 进行修改,如下所示:
#include <stdio.h>
#include <unistd.h> int main(int argc,char* argv[])
{
pid_t pid; printf("in program: %s, pid=%d\n",argv[],getpid()); execl("./test","test","aa",NULL); //指定test可执行文件在当前目录下
perror("execl"); printf("if execl execute successfull this statement never reach");
return ;
}
    test.c 文件如下:
#include <stdio.h>
#include <stdlib.h> int main(int argc,char* argv[])
{
pid_t pid; printf("in program: %s, pid=%d\n",argv[],getpid()); return ;
}
    测试结果如下:
[root@localhost fork]# gcc main.c
[root@localhost fork]# gcc -o test test.c
[root@localhost fork]# ./a.out
in program: ./a.out, pid= //执行a.out ,并加载启动 test 可知文件
in program: test, pid= //test 可执行文件加启动成功
[root@localhost fork]#
    注意:
    a.out 和 test的 进程PID是一样的,这是因为 test 被加载到 a.out 的进程空间运行,没有创建新进程,所以
PID值是一样的,而且执行成功的话,会在 test 里面退出,而不是在 a.out 里面退出。
     注意main.c 里面的代码。
 
要点:
      注意execl/execlp 函数调用的时候,传递的参数关系。 a.out 中调用 execl的第二个参数对应 test.c 中的
main函数的 argv[0] .
       
3、fork机制
    类Unix系统都使用fork机制来创建新进程。
    我原来一直不明白为什么要用 fork 这个字符组来表示创建新进程,后来查看英语的解释,才发现 fork 的意思是
分叉、分支、叉子的意思,soga,就是这样。
 
    fork机制的要点是:  
            1、创建一个新的进程,新进程拥有自己独立的进程空间和进程上下文
            2、fork会将父进程的空间对内容,完全的复制到子进程空间。
            3、fork出来的子进程和父进程一样,从fork函数调用位置开始执行
            4、fork函数在父进程中返回子进程的进程ID,  fork函数在子进程中返回0; 在代码中利用返回值
                  确定是在父进程还是子进程中。
    fork的原型如下:
FORK()                    Linux Programmer’s Manual                   FORK()
NAME
fork - create a child process SYNOPSIS
#include <sys/types.h>
#include <unistd.h> pid_t fork(void);
    fork测试代码如下:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h> int main(int argc,char* argv[])
{
pid_t pid; //创建新进程
pid=fork();
if( ==pid ) // 如果pid==0 则表示在子进程的进程空间
{
//下面的代码在子进程的进程空间执行
printf("Now you a in child process\n");
printf("my pid= %d\n",getpid());
printf("the process that create me is :%d\n",getppid());
exit(); //在子进程中退出
} //下面的代码在父进程的空间执行
printf("my pid= %d\n",getpid());
printf("the process that create me is :%d\n",getppid()); return ;
}
代码执行效果如下所示:
[root@localhost fork]# vim fork.c
[root@localhost fork]# gcc fork.c
[root@localhost fork]# ./a.out //第一次执行
Now you a in child process //子进程空间
my pid= //父进程空间
my pid= //子进程空间
the process that create me is : //子进程空间
the process that create me is : //父进程空间
[root@localhost fork]# ./a.out //第二次执行
Now you a in child process //子进程空间
my pid= //子进程空间
the process that create me is : //子进程空间
my pid= //父进程空间
the process that create me is : //父进程空间
[root@localhost fork]#
    可以发现子进程和父进程的执行顺序存在很大的随机性;父进程可能先执行,也可能后执行。有可能两个进程执行
是交叉的。
    
    有时候为了防止这种交叉性,可以在进程中等待其他进程执行完毕后再执行本进程的代码。在linux中利用wait( )实现
进程间的这种等待(又叫做同步)。
     wait的原型如下:
WAIT()                    Linux Programmer’s Manual                   WAIT()
NAME
wait, waitpid - wait for process to change state //等待某一个进程的状态的改变
SYNOPSIS
#include <sys/types.h>
#include <sys/wait.h> pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
    具体的描述信息:
    All  of  these  system  calls are used to wait for state changes in a child of the
calling process, and obtain information about the child whose state has changed.
A state change is considered to be: the child terminated; the child was stopped by
a signal; or the child was resumed by a signal. In the case of a terminated
child, performing a wait allows the system to release the resources associated
with the child; if a wait is not performed, then terminated the child remains in a
"zombie" state (see NOTES below).
        要点:
                    1、 这些函数用在调用这些函数的进程中等待子进程的状态改变。
                    2、子进程的状态改变有三种形式:    子进程终止、子进程暂停、子进程从暂停状态中恢复执行。
                    3、如果子进程的状态改变,这些函数立即返回,否则就阻塞调用 wait*( )函数的进程。
          wait( )等待所有的子进程中的某一个进程状态改变,相当于 waitpid(-1, &status, 0)
          waitpid()等待指定子进程的状态改变。这个函数需要注意。
          pid_t waitpid(pid_t pid,    //指定要等待的进程,-1 表示等待所有的子进程,>0 表示指定的子进程ID 
                                            int *status,
                                            int options); //指定要等待进程的什么状态
      pid 和 options 还有很多的取值,需要查看 mannual 手册。  
  
Exp: 测试一下, 先测试 wait()
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h> int main(int argc,char* argv[])
{
pid_t pid;
int status; //创建新进程
pid=fork();
if( ==pid )
{
printf("Now you a in child process ");
printf("my pid= %d\n",getpid());
printf("the process that create me is :%d\n\n",getppid());
exit();
}
//等待子进程的状态改变, 只有子进程的状态改变了wait才能返回,否则就阻塞父进程
wait(&status); printf("my pid= %d\n",getpid());
printf("the process that create me is :%d\n",getppid()); return ;
}
 这段代码编译后,无论怎么执行都会是下面的结果:
[root@localhost fork]# gcc fork.c
[root@localhost fork]# ./a.out //第一次执行
Now you a in child process my pid=
the process that create me is : my pid=
the process that create me is :
[root@localhost fork]# ./a.out //第二次执行
Now you a in child process my pid=
the process that create me is : my pid=
the process that create me is :
[root@localhost fork]#
    两次执行的情况都是 子进程先执行, 父进程后进行。  
Exp: 测试waitpid()
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h> int main(int argc,char* argv[])
{
pid_t pid;
int status; //创建新进程
pid=fork();
if( ==pid )
{
sleep();
printf("Now you a in child process ");
printf("my pid= %d\n",getpid());
printf("the process that create me is :%d\n",getppid());
exit();
} //等待子进程的状态改变
//wait(&status);
waitpid(pid,&status,WNOHANG);//函数立即返回,并且通过输出参数status获取子进程的状态 printf("my pid= %d\n",getpid());
printf("the process that create me is :%d\n",getppid()); return ;
}
执行情况如下:
[root@localhost fork]# gcc fork.c
[root@localhost fork]# ./a.out
my pid= //父进程中waitpid 已经返回
the process that create me is : //父进程输出信息后已经结束
[root@localhost fork]# Now you a in child process my pid= //子进程开始输出信息,
the process that create me is : [root@localhost fork]#
4、进程间同步
    如果在父子进程间同时操作一个文件,那么就会存在对文件操作的竞争状态,可能是文件的内容出现异常。
可以通过进程间同步机制完成进程间的同步。
   
    下面为测试代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
#include <fcntl.h> int main(int argc,char* argv[])
{
pid_t pid;
int status;
int fd;
char buf[];
int size;
int i;
int j; fd=open("./txt",O_RDWR | O_CREAT | O_TRUNC);
if(- == fd)
{
perror("open txt");
exit();
} //创建新进程
pid=fork();
if( ==pid )
{
for(i=;i<;i++)
{
j=;
size=sprintf(buf,"in child process pid=%d ppid=%d i=%d\n",getpid(), getppid(),i);
while(buf[j])
{
usleep();
write(fd,&buf[j++],);
}
}
exit();
} for(i=;i<;i++)
{
j=;
size=sprintf(buf,"in parent process pid=%d ppid=%d i=%d\n",getpid(), getppid(),i);
while(buf[j])
{
write(fd,&buf[j++],);
usleep();
}
}
//waitpid(pid,&status,WNOHANG);//函数立即返回,并且通过输出参数status获取子进程的状态 close(fd);
return ;
}
    生成的txt 文件如下所示:
in ipnar ecnth i plrocde spsr opcieds=s2 7p8i4d3=  7p8p4i4d = 7p1p4i di==
8i4n3 pia=r0e
nitn cphriolcde spsr opcieds=s2 7p8i4d3= 7p8p4i4d = 7p1p4i di==
8i4n3 pia=r1e
nitn cphriolcde spsr opcieds=s2 7p8i4d3= 7p8p4i4d = 7p1p4i di==
8i4n3 pia=r2e
nitn cphriolcde spsr opcieds=s2 7p8i4d3= 7p8p4i4d = 7p1p4i di==
8i4n3 pia=r3e
nitn cphriolcde spsr opcieds=s2 7p8i4d3= 7p8p4i4d = 7p1p4i di==
8i4n3 pia=r4e
nitn cphriolcde spsr opcieds=s2 7p8i4d3= 7p8p4i4d = 7p1p4i di==
8i4n3 pia=r5e
nitn cphriolcde spsr opcieds=s2 7p8i4d3= 7p8p4i4d = 7p1p4i di==
8i4n3 pia=r6e
nitn cphriolcde spsr opcieds=s2 7p8i4d3= 7p8p4i4d = 7p1p4i di==
8i4n3 pia=r7e
nitn cphriolcde spsr opcieds=s2 7p8i4d3= 7p8p4i4d = 7p1p4i di==
8i4n3 pia=r8e
nitn cphriolcde spsr opcieds=s2 7p8i4d3= 7p8p4i4d = 7p1p4i di==
i=
    生成的信息,是乱码,不能传递信息。
 
    修改fork.c  如下:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
#include <fcntl.h> int main(int argc,char* argv[])
{
pid_t pid;
int status;
int fd;
char buf[];
int size;
int i;
int j; fd=open("./txt",O_RDWR | O_CREAT | O_TRUNC);
if(- == fd)
{
perror("open txt");
exit();
} //创建新进程
pid=fork();
if( ==pid )
{
for(i=;i<;i++)
{
j=;
size=sprintf(buf,"in child process pid=%d ppid=%d i=%d\n",getpid(), getppid(),i);
while(buf[j])
{
usleep();
write(fd,&buf[j++],);
}
}
exit();
} wait(&status); //等待子进程状态改变,新增加的代码
for(i=;i<;i++)
{
j=;
size=sprintf(buf,"in parent process pid=%d ppid=%d i=%d\n",getpid(), getppid(),i);
while(buf[j])
{
write(fd,&buf[j++],);
usleep();
}
}
//waitpid(pid,&status,WNOHANG);//函数立即返回,并且通过输出参数status获取子进程的状态 close(fd);
return ;
}
      生成的TXT文件如下所示:
in child process pid=  ppid= i=
in child process pid= ppid= i=
in child process pid= ppid= i=
in child process pid= ppid= i=
in child process pid= ppid= i=
in child process pid= ppid= i=
in child process pid= ppid= i=
in child process pid= ppid= i=
in child process pid= ppid= i=
in child process pid= ppid= i=
in parent process pid= ppid= i=
in parent process pid= ppid= i=
in parent process pid= ppid= i=
in parent process pid= ppid= i=
in parent process pid= ppid= i=
in parent process pid= ppid= i=
in parent process pid= ppid= i=
in parent process pid= ppid= i=
in parent process pid= ppid= i=
in parent process pid= ppid= i=

  【linux草鞋应用编程系列】_2_环境变量和进程控制

  本系列文章未完,待续。

  如果您发现,文章有疏漏之处请不吝指教,包括错别字,标点符号等任何错误。

【linux草鞋应用编程系列】_2_ 环境变量和进程控制的更多相关文章

  1. 【linux草鞋应用编程系列】_3_ 进程间通信

    一.进程间通信        linux下面提供了多种进程间通信的方法, 管道.信号.信号量.消息队列.共享内存.套接字等.下面我们分别 介绍管道.信号量.消息队列.共享内存.        信号和套 ...

  2. 【linux草鞋应用编程系列】_5_ Linux网络编程

    一.网络通信简介   第一部分内容,暂时没法描述,内容实在太多,待后续专门的系列文章.   二.linux网络通信     在linux中继承了Unix下“一切皆文件”的思想, 在linux中要实现网 ...

  3. 【linux草鞋应用编程系列】_4_ 应用程序多线程

    一.应用程序多线程     当一个计算机上具有多个CPU核心的时候,每个CPU核心都可以执行代码,此时如果使用单线程,那么这个线程只能在一个 CPU上运行,那么其他的CPU核心就处于空闲状态,浪费了系 ...

  4. 【linux草鞋应用编程系列】_1_ 开篇_系统调用IO接口与标准IO接口

    最近学习linux系统下的应用编程,参考书籍是那本称为神书的<Unix环境高级编程>,个人感觉神书不是写给草鞋看的,而是 写给大神看的,如果没有一定的基础那么看这本书可能会感到有些头重脚轻 ...

  5. 【linux草鞋应用编程系列】_6_ 重定向和VT100编程

    一.文件重定向     我们知道在linux shell 编程的时候,可以使用文件重定向功能,如下所示: [root@localhost pipe]# echo "hello world&q ...

  6. linux下查看和添加PATH环境变量

    linux下查看和添加PATH环境变量 $PATH:决定了shell将到哪些目录中寻找命令或程序,PATH的值是一系列目录,当您运行一个程序时,Linux在这些目录下进行搜寻编译链接. 编辑你的 PA ...

  7. Linux操作系统下三种配置环境变量的方法

    现在使用linux的朋友越来越多了,在linux下做开发首先就是需要配置环境变量,下面以配置java环境变量为例介绍三种配置环境变量的方法. 1.修改/etc/profile文件 如果你的计算机仅仅作 ...

  8. Linux 下三种方式设置环境变量

    1.在Windows 系统下,很多软件安装都需要配置环境变量,比如 安装 jdk ,如果不配置环境变量,在非软件安装的目录下运行javac 命令,将会报告找不到文件,类似的错误. 2.那么什么是环境变 ...

  9. Linux操作系统下三种配置环境变量的方法——转载

    来源:赛迪网 作者:millio       现在使用linux的朋友越来越多了,在linux下做开发首先就是需要配置环境变量,下面以配置java环境变量为例介绍三种配置环境变量的方法. 1.修改/e ...

随机推荐

  1. .Net组件程序设计之远程调用(二)

    .Net组件程序设计之远程调用(二) 激活模式 引用封送对象激活类型两种, 一种是客户端激活类型,一种是服务器端激活. 客户端激活对象 客户端激活方式:当客户端创建一个远程对象时,客户端得到的是一个新 ...

  2. Functional Programming without Lambda - Part 1 Functional Composition

    Functions in Java Prior to the introduction of Lambda Expressions feature in version 8, Java had lon ...

  3. JS实战 · 仿css样式选择器

    代码如下: <html> <head>     <meta http-equiv="Content-Type" content="text/ ...

  4. css垂直居中那点事

    这是我技术博客生涯的第一篇文章,想想还是有点小鸡冻...菜鸟的征程现在要开始了 学习css的时候经常被各种问题纠结到不要不要的,没办法,只能写写博客帮助整理一下自己的思绪和帮助一下和我遇到同样问题的小 ...

  5. [译]AngularJS $apply, $digest, 和$evalAsync的比较

    原文:The differences between AngularJS $apply, $digest, and $evalAsync 你是不是也常在想AngularJS $apply, $dige ...

  6. 剖析twemproxy前言

    又是喜闻乐见的新坑,前面的mysql协议,当我在解读go-mysql包的时候,会重新讲到,至于Leetcode的更新会与go语言同步.关于这个redis的新坑,目前打算通过剖析twemproxy源码来 ...

  7. Constraint4:default约束

    Default约束的作用是在insert语句执行时,如果未显式给指定的column赋值,那么使用默认值给column赋值:如果在Insert命令中显式为指定的Column赋值,那么将插入显式值.每一列 ...

  8. 解密jQuery事件核心 - 模拟事件(四)

    前几章已经把最核心的实现都分解过了,这一章我们看看jQuery是如何实现事件模拟的 在Internet Explorer 8和更低,一些事件change 和 submit本身不冒泡,但jQuery修改 ...

  9. 解决adb.exe' and can be executed.

    百度google大家多说的是任务管理器 kill掉adb 或者重启adb server,但我任务管理器就没有adb ,猜测是某个程序占用了adb端口.于是按此思路查找. 5037为adb默认端口 查看 ...

  10. Lua 学习笔记(十)数据结构

    在Lua中的table不是一种简单的数据结构,它可以作为其他数据结构的基础.其他语言提供的数据结构,如数组.记录.线性表.队列.集合等,在Lua中都可以通过table来表示.而且使用Lua实现这些数据 ...