一、 环境变量

应用程序在执行的时候,可能需要获取系统的环境变量,从而执行一些相应的操作。
在linux中有两种方法获取环境变量,分述如下。
1、通过main函数的参数获取环境变量
main函数的多种定义方式:

     int main(void);int main(int argc, char* argv[ ]);int main(int argc, char* argv[ ],  char* env[ ] )

View Code

方式1和方式2比较常见,下面介绍一下方式3: 第三个参数获取系统的环境变量。
Exp:
#include <stdio.h>int main(int argc,char* argv[], char* env[])
{int i=0;while(env[i]){puts(env[i++]);}return 0;
}

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

2、访问全局变量 environ 获取环境变量
在加载应用程序的时候,linux系统会为每一个应用程序复制一份系统环境变量副本,保存在全局变量 enviro 中。
可以通过这个全局的变量访问系统的环境变量。
Exp:
#include <stdio.h>extern char** environ;int main(int argc,char* argv[])
{int i=0;while(environ[i]){puts(environ[i++]);}return 0;
}

3、获取指定的环境变量

linux提供环境变量操作相关的函数: getenv( )、putenv( )、setenv()、unsetenv()、clearenv( ).
getenv( )
GETENV(3)                  Linux Programmer’s Manual                 GETENV(3)
NAMEgetenv - get an environment variableSYNOPSIS#include <stdlib.h>char *getenv(const char *name);    //要获取的环境变量,比方说传递的是 "HOME" ,将返回HOME的值

返回值:
成功返回指向环境变量的值的指针,失败返回NULL。
putenv( )
UTENV(3)                  Linux Programmer’s Manual                 PUTENV(3)
NAMEputenv - change or add an environment variable   //增加或者改变环境变量的值
SYNOPSIS#include <stdlib.h>int putenv(char *string);    //设置的环境变量字符串, string的格式如下:  HOME=/home/volcanol

setenv( ) 和 unsetenv()

SETENV(3)                  Linux Programmer’s Manual                 SETENV(3)
NAMEsetenv - 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);    //要删除的环境变量

DESCRIPTIONThe  setenv()  function  adds  the  variable name to the environment with the valuevalue, if name does not already exist.  If name does exist in the environment, thenits  value is changed to value if overwrite is non-zero; if overwrite is zero, thenthe value of name is not changed.The unsetenv() function deletes the variable name from the environment.

注意:

unsetenv 会将环境变量删除,包括环境变量的名和环境变量的值
clearenv()清除所有的环境变量,并设置environ 的值为NULL。
CLEARENV(3)                                                                                              CLEARENV(3)
NAMEclearenv - clear the environment
SYNOPSIS#include <stdlib.h>int clearenv(void);
DESCRIPTIONThe clearenv() function clears the environment of all name-value pairs and sets thevalue 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", 1);env=getenv("Test-env");printf("the Test-env is: %s\n ",env);return 0;
}

执行结果如下:
[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 0;
}

执行结果如下:
[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=0;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 0;
}

执行结果如下:
[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(2)                  Linux Programmer’s Manual                 GETPID(2)
NAMEgetpid, getppid - get process identification
SYNOPSIS#include <sys/types.h>#include <unistd.h>pid_t getpid(void);pid_t getppid(void);DESCRIPTIONgetpid()  returns  the  process  ID of the current process.  (This is often used byroutines 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 0;
}

程序执行结果如下:
[root@localhost fork]# ./a.out
pid=19077, ppid=714
[root@localhost fork]# ps aux | grep "bash"
root       714  0.0  0.3   5940  1668 pts/1    Ss   04:46   0:01 bash

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

bash 这个进程创建的,因此./a.out 的父进程的PID为 714。
2、执行其他程序
linux下提供 一个函数族 在进程中执行其他应用程序。函数族为  exec 。其原型如下:
EXEC(3)                    Linux Programmer’s Manual                   EXEC(3)NAMEexecl, execlp, execle, execv, execvp - execute a fileSYNOPSIS#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[0],getpid());execl("test","from caller",NULL);  //exec从默认路径搜索 test 可执行文件,我系统中默认路径没有  test 可知文件,执行会失败perror("execl");return 0;
}

下面的文件是生成 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[1],getpid());return 0;
}

执行结果如下:

[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=19402
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[0],getpid());execl("./test","test","aa",NULL);    //指定test可执行文件在当前目录下perror("execl");printf("if execl execute successfull this statement never reach");return 0;
}

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[0],getpid());return 0;
}

测试结果如下:
[root@localhost fork]# gcc main.c
[root@localhost fork]# gcc -o test test.c
[root@localhost fork]# ./a.out
in program: ./a.out, pid=19836     //执行a.out  ,并加载启动 test 可知文件
in program: test, pid=19836         //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(2)                    Linux Programmer’s Manual                   FORK(2)
NAMEfork - create a child processSYNOPSIS#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( 0==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(0);   //在子进程中退出
    }//下面的代码在父进程的空间执行printf("my pid= %d\n",getpid());printf("the process that  create me is :%d\n",getppid());return 0;
}

代码执行效果如下所示:
[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= 22333   //父进程空间
my pid= 22334   //子进程空间
the process that  create me is :22333  //子进程空间
the process that  create me is :714     //父进程空间
[root@localhost fork]# ./a.out      //第二次执行
Now you a in child process         //子进程空间
my pid= 22337            //子进程空间
the process that  create me is :22336 //子进程空间
my pid= 22336             //父进程空间
the process that  create me is :714      //父进程空间
[root@localhost fork]# 

可以发现子进程和父进程的执行顺序存在很大的随机性;父进程可能先执行,也可能后执行。有可能两个进程执行
是交叉的。
有时候为了防止这种交叉性,可以在进程中等待其他进程执行完毕后再执行本进程的代码。在linux中利用wait( )实现
进程间的这种等待(又叫做同步)。
wait的原型如下:
WAIT(2)                    Linux Programmer’s Manual                   WAIT(2)
NAMEwait, 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 thecalling 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 bya signal; or the child was resumed by a signal.   In  the  case  of  a  terminatedchild,  performing  a  wait  allows the system to release the resources associatedwith 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( 0==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(0);}//等待子进程的状态改变, 只有子进程的状态改变了wait才能返回,否则就阻塞父进程wait(&status);  printf("my pid= %d\n",getpid());printf("the process that  create me is :%d\n",getppid());return 0;
}

这段代码编译后,无论怎么执行都会是下面的结果:
[root@localhost fork]# gcc fork.c
[root@localhost fork]# ./a.out                      //第一次执行
Now you a in child process my pid= 24896
the process that  create me is :24895my pid= 24895
the process that  create me is :714
[root@localhost fork]# ./a.out                      //第二次执行
Now you a in child process my pid= 24898
the process that  create me is :24897my pid= 24897
the process that  create me is :714
[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( 0==pid ){sleep(5);printf("Now you a in child process ");printf("my pid= %d\n",getpid());printf("the process that  create me is :%d\n",getppid());exit(0);}//等待子进程的状态改变//wait(&status);waitpid(pid,&status,WNOHANG);//函数立即返回,并且通过输出参数status获取子进程的状态
printf("my pid= %d\n",getpid());printf("the process that  create me is :%d\n",getppid());return 0;
}

执行情况如下:
[root@localhost fork]# gcc fork.c
[root@localhost fork]# ./a.out
my pid= 25808                 //父进程中waitpid 已经返回
the process that  create me is :714    //父进程输出信息后已经结束
[root@localhost fork]# Now you a in child process my pid= 25809    //子进程开始输出信息,
the process that  create me is :1[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[128];int size;int i;int j;fd=open("./txt",O_RDWR | O_CREAT | O_TRUNC);if(-1 == fd){perror("open txt");exit(0);}//创建新进程pid=fork();if( 0==pid ){ for(i=0;i<10;i++){j=0;size=sprintf(buf,"in child process pid=%d  ppid=%d i=%d\n",getpid(), getppid(),i);while(buf[j])   {usleep(2);write(fd,&buf[j++],1);}}exit(0);}for(i=0;i<10;i++){j=0;size=sprintf(buf,"in parent  process pid=%d  ppid=%d i=%d\n",getpid(), getppid(),i);while(buf[j]){write(fd,&buf[j++],1);usleep(2);}}//waitpid(pid,&status,WNOHANG);//函数立即返回,并且通过输出参数status获取子进程的状态
   close(fd);return 0;
}

生成的txt 文件如下所示:
in ipnar ecnth i plrocde spsr opcieds=s2 7p8i4d3= 2 7p8p4i4d = 7p1p4i di==207
8i4n3  pia=r0e
nitn   cphriolcde spsr opcieds=s2 7p8i4d3= 2 7p8p4i4d = 7p1p4i di==217
8i4n3  pia=r1e
nitn   cphriolcde spsr opcieds=s2 7p8i4d3= 2 7p8p4i4d = 7p1p4i di==227
8i4n3  pia=r2e
nitn   cphriolcde spsr opcieds=s2 7p8i4d3= 2 7p8p4i4d = 7p1p4i di==237
8i4n3  pia=r3e
nitn   cphriolcde spsr opcieds=s2 7p8i4d3= 2 7p8p4i4d = 7p1p4i di==247
8i4n3  pia=r4e
nitn   cphriolcde spsr opcieds=s2 7p8i4d3= 2 7p8p4i4d = 7p1p4i di==257
8i4n3  pia=r5e
nitn   cphriolcde spsr opcieds=s2 7p8i4d3= 2 7p8p4i4d = 7p1p4i di==267
8i4n3  pia=r6e
nitn   cphriolcde spsr opcieds=s2 7p8i4d3= 2 7p8p4i4d = 7p1p4i di==277
8i4n3  pia=r7e
nitn   cphriolcde spsr opcieds=s2 7p8i4d3= 2 7p8p4i4d = 7p1p4i di==287
8i4n3  pia=r8e
nitn   cphriolcde spsr opcieds=s2 7p8i4d3= 2 7p8p4i4d = 7p1p4i di==297
843 i=9

生成的信息,是乱码,不能传递信息。
修改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[128];int size;int i;int j;fd=open("./txt",O_RDWR | O_CREAT | O_TRUNC);if(-1 == fd){perror("open txt");exit(0);}//创建新进程pid=fork();if( 0==pid ){ for(i=0;i<10;i++){j=0;size=sprintf(buf,"in child process pid=%d  ppid=%d i=%d\n",getpid(), getppid(),i);while(buf[j])   {usleep(2);write(fd,&buf[j++],1);}}exit(0);}wait(&status);     //等待子进程状态改变,新增加的代码for(i=0;i<10;i++){j=0;size=sprintf(buf,"in parent  process pid=%d  ppid=%d i=%d\n",getpid(), getppid(),i);while(buf[j]){write(fd,&buf[j++],1);usleep(2);}}//waitpid(pid,&status,WNOHANG);//函数立即返回,并且通过输出参数status获取子进程的状态
    close(fd);return 0;
}

生成的TXT文件如下所示:
in child process pid=27878  ppid=27877 i=0
in child process pid=27878  ppid=27877 i=1
in child process pid=27878  ppid=27877 i=2
in child process pid=27878  ppid=27877 i=3
in child process pid=27878  ppid=27877 i=4
in child process pid=27878  ppid=27877 i=5
in child process pid=27878  ppid=27877 i=6
in child process pid=27878  ppid=27877 i=7
in child process pid=27878  ppid=27877 i=8
in child process pid=27878  ppid=27877 i=9
in parent  process pid=27877  ppid=714 i=0
in parent  process pid=27877  ppid=714 i=1
in parent  process pid=27877  ppid=714 i=2
in parent  process pid=27877  ppid=714 i=3
in parent  process pid=27877  ppid=714 i=4
in parent  process pid=27877  ppid=714 i=5
in parent  process pid=27877  ppid=714 i=6
in parent  process pid=27877  ppid=714 i=7
in parent  process pid=27877  ppid=714 i=8
in parent  process pid=27877  ppid=714 i=9

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

  本系列文章未完,待续。

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

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

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

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

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

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

  3. Linux系统编程--2(环境变量,进程控制)

    环境变量 环境变量 是指在操作系统中用来指定操作系统运行环境的一些参数 每个人用电脑的习惯不一样,比如一般把文件放到磁盘,怎么管理文件,用什么编译器,所以,环境变量就是根据每个人使用操作系统的习惯来规 ...

  4. Linux配置示例:配置java环境变量

    1.修改/etc/profile文件   如果你的计算机仅仅作为开发使用时推荐使用这种方法,因为所有用户的shell都有权使用这些环境变量,可能会给系统带来安全性问题. (1)用文本编辑器打开/etc ...

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

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

  6. linux共享库位置配置(LD_LIBRARY_PATH环境变量 或者 更改/etc/ld.so.conf)

    linux共享库位置配置(LD_LIBRARY_PATH环境变量 或者 更改/etc/ld.so.conf) 转载于:https://www.cnblogs.com/RichardLee/archiv ...

  7. 【Linux】5.linux下的export命令和环境变量

    linux下的export命令和环境变量 linux中在 profile 或者 bashrc 或者其他类似的文件中设置环境变量时(比如PATH),如果没有export,那么只能在直接启动的shell中 ...

  8. Linux操作系统下三种配置环境变量的方法(linux下几种profile执行顺序)

    http://www.linuxeden.com/html/sysadmin/20080424/56879.html 现在使用linux的朋友越来越多了,在linux下做开发首先就是需要配置环境变量, ...

  9. [zz]Linux操作系统下三种配置环境变量的方法

    个人的总结: 设置了/etc/profile 和 ~/.bashrc 之后,使用了source 命令,是可以echo添加的变量,但是用getenv读不出来,然后使用env命令也显示不出来,是因为没有e ...

最新文章

  1. Java项目如何改成maven_普通java项目改进为maven:ecplise
  2. 剑指offer(34-40题)详解
  3. 敏捷项目计划的多层面
  4. java 中如何实现多进程_在Java中可以使用哪些方法来实现Java的多进程运行模式?...
  5. 5 篇 AAAI 2018 论文看「应答生成」
  6. boost::hana::infix用法的测试程序
  7. 1 客户端性能--浏览器页面处理
  8. 远程连接mysql数据库注意点记录
  9. 高考610考哪个计算机学校,2019年高考成绩610分_615分左右能报考上什么学校 文科理科大学名单推荐...
  10. 微信计步器怎么不计步_难以关闭的微信朋友圈广告
  11. http://selectorgadget.com/
  12. Windows系统 services.msc命令详解,Windows命令行查看本地服务
  13. gitgrab.sh
  14. 基于MBR 的bootkit的进展 鬼影-TDL4-BMW
  15. java cmd 编译jar_Java程序在命令行下编译运行打Jar包
  16. ioncube linux,linux 下ionCube安装
  17. Invalid data found when processing input
  18. “狼来了”的VR风,占领不了的客厅
  19. 强大的chrome(1)以acfun为例抓取视频
  20. 大容量小体积的固态U盘,读写速度超快,大华S809体验

热门文章

  1. Visual Studio 2017创建XAML文件
  2. AppleWatch开发教程之调试程序使用帮助文档
  3. OUYA游戏开发快速入门教程第1章了解OUYA及其设备
  4. 邀请别人进入队伍rust_林俊杰组建DOTA2队伍,原Newbee五人被终身禁赛
  5. oracle中or的替函数,Oracle常用内置Or自定义函数-SQL宝典
  6. quicklook不能预览office_万物皆可格!给空格键施加神奇魔法的神器软件—快速预览工具QuicklookPC软件...
  7. java线程能做什么_java中的多线程能做什么 ?基本作用能说下吗?
  8. mysql 前后代表什么_MySQL的锁
  9. Cell子刊:MRI有助于揭示睡眠之谜
  10. 科学家提出了忆阻性神经混合芯片 这一概念