随笔 - 63  文章 - 0  trackbacks - 0
<2018年10月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

常用链接

留言簿

随笔分类

随笔档案

收藏夹

调试技巧

搜索

  •  

最新评论

阅读排行榜

评论排行榜

1.下载并安装python-dev
    sudo apt-get install python-dev
2.下载并解压distcc:
    tar xvf distcc-3.2rc1.tar.bz2
3.配置
    cd distcc-3.2rc1/
    ./configure --prefix=/home/you/distcc-install --disable-Werror
4.安装
    make install
5.运行
    服务端运行 
        export PATH=$PATH:服务端distcc程序路径:服务器编译工具路径
        distcc --deamon --allow 192.168.0.0/16  --job 8 --user nobody
    客户端运行 :
        export PATH=$PATH:客户端distcc程序路径:客户端编译工具路径
        export DISTCC_HOSTS="server_ip1 server_ip2 ..."
        make -j8 CC=distcc
6、cmake
cd build/
CC="distcc cc" CXX="distcc g++" cmake ../cmake/
posted @ 2018-09-08 20:56 长戟十三千 阅读(24) | 评论 (0)编辑 收藏
TcMalloc(Thread-CachingMalloc)是google-perftools工具中的一个内存管理库,与标准的glibc库中malloc相比,TcMalloc在内存分配的效率和速度上要高很多,可以提升高并发情况下的性能,降低系统的负载。
Google-perftools项目的网址为:http://code.google.com/p/google-perftools/,该项目包括TcMalloc、heap-checker、heap-profiler和cpu-profiler共4个组件。在只使用TcMalloc情况下可以不编译其他三个组件。
注:使用线程内存池的方法,在小对象是在内存池中进行分配,使用分配较多的内存空间来优化分配时间。
实现原理请参考网址http://goog-perftools.sourceforge.net/doc/tcmalloc.html

简介

TcMalloc是一个由Google开发的,比glibc的malloc更快的内存管理库。通常情况下ptmalloc2能在300ns执行一个malloc和free对,而TcMalloc能在50ns内执行一个malloc和free对。
TcMalloc可以减少多线程程序之间的锁争用问题,在小对象上能达到零争用。
TcMalloc为每个线程单独分配一个线程本地的Cache,少量的地址分配就直接从Cache中分配,并且定期做垃圾回收,将线程本地Cache中的空闲内存返回给全局控制堆。
TcMalloc认为小于(<=)32K为小对象,大对象直接从全局控制堆上以页(4K)为单位进行分配,也就是说大对象总是页对齐的。
TcMalloc中一个页可以存入一些相同大小的小对象,小对象从本地内存链表中分配,大对象从中心内存堆中分配。

安装

Linux下tcmalloc的安装过程如下:
1)  从Google源代码网址上下载源代码包,现在最新版本为2.0;
2)  解压缩源代码包
# unzip gperftools-2.0.zip          或
# tar zxvf gperftools-2.0.tar.gz
3)  编译动态库
# cd gperftools-2.0
# ./ configure  --disable-cpu-profiler --disable-heap-profiler--disable-heap-checker 
--disable-debugalloc--enable-minimal
加入上面的参数是为了只生成tcmalloc_minimal动态库,如果需要所有组件,命令如下:
# ./configure
# ./configure -h           用于查看编译选项。
编译和安装:
# make&& make install
使用最小安装时把tcmalloc_minimal的动态库拷贝到系统目录中:
# cplib/tcmalloc_minimal.so.0.0.0 /usr/local/lib
创建软连接指向tcmalloc:
# ls –s /usr/local/lib/libtcmalloc_minimal.so.0.0.0/usr/local/lib/libtcmalloc.so
启动程序之前,预先加载tcmalloc动态库的环境变量设置:
# exportLD_PRELOAD=”/usr/local/lib/libtcmalloc.so
使用losf检查程序是否已经加载tcmalloc库:
# lsof -n | greptcmalloc
在Linux下使用的tcmalloc安装完成,在Windows下使用VS(2003以上版本)打开工程项目gperftools.sln进行编译。

使用

将libtcmalloc.so/libtcmalloc.a链接到程序中,或者设置LD_PRELOAD=libtcmalloc.so。这样就可以使用tcmalloc库中的函数替换掉操作系统的malloc、free、realloc、strdup内存管理函数。可以设置环境变量设置如下:
         TCMALLOC_DEBUG=<level>       调试级别,取值为1-2
         MALLOCSTATS=<level>                    设置显示内存使用状态级别,取值为1-2
         HEAPPROFILE=<pre>                     指定内存泄露检查的数据导出文件
         HEAPCHECK=<type>                        堆检查类型,type=normal/strict/draconian
TcMalloc库还可以进行内存泄露的检查,使用这个功能有两种方法:
1)将tcmalloc库链接到程序中,注意应该将tcmalloc库最后链接到程序中;
2)设置LD_PRELOAD=”libtcmalloc.so”/HEAPCHECK=normal,这样就不需重新编译程序
打开检查功能,有两种方式可以开启泄露检查功能:
1)  使用环境变量,对整个程序进行检查: HEAPCHECK=normal /bin/ls
2)  在源代码中插入检查点,这样可以控制只检查程序的某些部分,代码如下:
HeapProfileLeakCheckerchecker("foo");        // 开始检查
Foo();                                                                         // 需要检查的部分
assert(checker.NoLeaks());                                 // 结束检查
调用checker建立一个内存快照,在调用checker.NoLeaks建立另一个快照,然后进行比较,如果内存有增长或者任意变化,NoLeaks函数返回false,并输出一个信息告诉你如何使用pprof工具来分析具体的内存泄露。
    执行内存检查:
         #LD_PRELOAD=libtcmalloc.so HEAPCHECK=strict HEAPPROFILE=memtm ./a.out
执行完成后会输出检查的结果,如果有泄露,pprof会输出泄露多少个字节,有多少次分配,也会输出详细的列表指出在什么地方分配和分配多少次。
         比较两个快照:
         #pprof --base=profile.0001.heap 程序名 profile.0002.heap
    已知内存泄漏时,关闭内存泄露检查的代码:
void *mark =HeapLeakChecker::GetDisableChecksStart();
<leaky code>           //不做泄漏检查的部分
HeapLeakChecker::DisableChecksToHereFrom(mark);
         注:在某些libc中程序可能要关闭检查才能正常工作。
         注:不能检查数组删除的内存泄露,比如:char *str = new char[100]; delete str;。


=================================安装缺少库============================

libunwind库为基于64位CPU和操作系统的程序提供了基本的堆栈辗转开解功能,其中包括用于输出堆栈跟踪的API、用于以编程方式辗转开解堆栈的API以及支持C++异常处理机制的API。

64位操作系统一定要先装libunwind这个库。

wget http://download.savannah.gnu.org/releases/libunwind/libunwind-1.1.tar.gz

tar zxvf libunwind-1.1.tar.gz
cd libunwind-1.1
CFLAGS=-fPIC ./configure
make CFLAGS=-fPIC
make CFLAGS=-fPIC install
posted @ 2018-08-24 11:22 长戟十三千 阅读(35) | 评论 (0)编辑 收藏

LINUX samba配置共享文件目录

 

1.使用rpm -qa|grep samba 查看是否安装samba

 

samba-winbind-clients-3.5.4-68.el6.x86_64

samba-3.5.4-68.el6.x86_64

samba-client-3.5.4-68.el6.x86_64

samba-common-3.5.4-68.el6.x86_64

已安装

2.更改/etc/samba/smb.conf配置

 

C代码
  1. [global] 
  2.     dos charset = cp936 
  3.     display charset = UTF-8 
  4.     workgroup = MYGROUP 
  5.     server string = Samba Server Version %v 
  6.     log file = /var/log/samba/log.%m 
  7.     max log size = 50 
  8.     cups options = raw 
  9.  
  10. [homes] 
  11.     comment = Home Directories 
  12.     read only = No 
  13.     browseable = No 
  14.  
  15. [printers] 
  16.     comment = All Printers 
  17.     path = /var/spool/samba 
  18.     printable = Yes 
  19.     browseable = No 
  20.  
  21. [tools] 
  22.     comment = tools 
  23.     path = /tools 
  24.     read only = No 
  25.     guest ok = Yes 
  26.  
  27. [home] 
  28.     comment = User Directory 
  29.     path = /home/%U 
  30.     read only = No 
[global] 	dos charset = cp936 	display charset = UTF-8 	workgroup = MYGROUP 	server string = Samba Server Version %v 	log file = /var/log/samba/log.%m 	max log size = 50 	cups options = raw  [homes] 	comment = Home Directories 	read only = No 	browseable = No  [printers] 	comment = All Printers 	path = /var/spool/samba 	printable = Yes 	browseable = No  [tools] 	comment = tools 	path = /tools 	read only = No 	guest ok = Yes  [home] 	comment = User Directory 	path = /home/%U 	read only = No

添加smb访问用户smbpasswd -a root

 

3.重启service smb restart

4.如果windows下登录samba服务器后无法访问linux下共享目录,提示没有权限。

则检查

 

a、确保linux下防火墙关闭或者是开放共享目录权限

 

b、确保samba服务器配置文件smb.conf设置没有问题,可网上查阅资料看配置办法  

c、确保setlinux关闭,可以用setenforce 0命令执行。 默认的,SELinux禁止网络上对Samba服务器上的共享目录进行写操作,即使你在smb.conf中允许了这项操作。       /usr/bin/setenforce 修改SELinux的实时运行模式  

setenforce 1 设置SELinux 成为enforcing模式

setenforce 0 设置SELinux 成为permissive模式  

如果要彻底禁用SELinux 需要在/etc/sysconfig/selinux中设置参数selinux=0 ,或者在/etc/grub.conf中添加这个参数

  /usr/bin/setstatus -v  

 

 

 

posted @ 2018-08-16 17:09 长戟十三千 阅读(11) | 评论 (0)编辑 收藏

gperftools是Google提供的一套工具,其中的一个功能是CPU profiler,用于分析程序性能,找到程序的性能瓶颈。 
Graphviz是一个由AT&T实验室启动的开源工具包,用于绘制DOT语言脚本描述的图形,gperftools依靠此工具生成图形分析结果。 
安装命令:yum install graphviz 
编译google-perftools 
因为我们只需要tcmalloc功能,因此不编译google-perftools中的其他工具。 
wget http://gperftools.googlecode.com/files/google-perftools-1.9.1.tar.gz 
tar -xvzf google-perftools-1.9.1.tar.gz 
cd google-perftools-1.9.1 
./configure –disable-cpu-profiler –disable-heap-profiler –disable-heap-checker –enable-minimal–disable-dependency-tracking 
make 
makeinstall 
/sbin/ldconfig 
用法 
1.目标程序中引入头文件

示例:

#include <google/profiler.h> #include <iostream> using namespace std; void func1() {    int i = 0;    while (i < 100000) {        ++i;    }   } void func2() {    int i = 0;    while (i < 200000) {        ++i;    }   } void func3() {    for (int i = 0; i < 1000; ++i) {        func1();        func2();    }   } int main(){    ProfilerStart("my.prof"); // 指定所生成的profile文件名    func3();    ProfilerStop(); // 结束profiling    return 0; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

然后编译链接运行,使用pprof生成分析结果 
g++-o demo demo.cpp -lprofiler 
运行demo,生成my.prof文件,然后用pprof命令对该文件解析,生成结果txt或pdf等。 
pprof–text ./demo my.prof > output.txt 
pprof–pdf ./demo my.prof > output.pdf

pdf格式的比较直观 
这里写图片描述
图形风格的结果由节点和有向边组成, 
每个节点代表一个函数,节点数据格式: 
Class Name 
Method Name 
local (percentage) 
of cumulative (percentage) 
local时间是函数直接执行的指令所消耗的CPU时间(包括内联函数)。性能分析通过抽样方法完成,默认是1秒100个样本,一个样本是10毫秒,即时间单位是10毫秒;cumulative时间是local时间与其他函数调用的总和;如果cumulative时间与local时间相同,则不打印cumulative时间项。 
有向边:调用者指向被调用者,有向边上的时间表示被调用者所消耗的CPU时间

如果生成pdf时报错:ps2pdf command not found,那么要安装Ghostscript。 
下载地址: 
http://www.linuxfromscratch.org/blfs/view/cvs/pst/gs.html 
百度地址: 
http://pan.baidu.com/s/1hsP2N56#list/path=%2F 
安装的时间会很长,要耐心等待。

文本风格输出结果 
Total: 116 samples 
83 71.6% 71.6% 83 71.6% func2 
33 28.4% 100.0% 33 28.4% func1 
0 0.0% 100.0% 116 100.0% __libc_start_main 
0 0.0% 100.0% 116 100.0% _start 
0 0.0% 100.0% 116 100.0% func3 
0 0.0% 100.0% 116 100.0% main 
一共6列,分别代表的意思是: 
分析样本数量(不包含其他函数调用) 
分析样本百分比(不包含其他函数调用) 
目前为止的分析样本百分比(不包含其他函数调用) 
分析样本数量(包含其他函数调用) 
分析样本百分比(包含其他函数调用) 
函数名

注意:

gperftools需要程序正常退出才能向prof文件打印数据,所以当程序无法退出时,得要发送信号给进程,在接到信号后,调用ProfilerStop();函数,才能打印出数据。如下所示:

void signal_handler(int signo) {     signal(signo, signal_handler);     INFO_LOG("recv signal[%d]", signo);     switch(signo)     {               case SIGTERM:              //程序自己退出,或shell里调用kill缺省该进程。该信号可以被阻塞,或被处理              //可以在这里做一些程序退出前的最后处理工作              ProfilerStop();              INFO_LOG("Process recieve SIGTERM");              break;           }     exit(0); } //主函数 signal(SIGTERM, &signal_handler);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

用valgrind的callgrind工具也可以进行分析程序性能。 
分享一个教程:http://www.tuicool.com/articles/nUZJBb2

posted @ 2018-07-13 13:47 长戟十三千 阅读(26) | 评论 (0)编辑 收藏

linux登录后有时候会出现-bash-4.1$

造成这样的原因: 
与这个用户有关环境变量没了,有关的文件被删除。也就是用户的家目录下面 .bash_profile .bashrc 被删除。

解决办法:

##首先切换到故障用户 su - test ##复制对应的文件(不要用root直接复制,否则复制过去的东西属主,数组都是root的) -bash-4.1$ cp /etc/skel/.bash*  ~  ##(/etc/skel 新用户老家的样子,所以从这里复制) -bash-4.1$ ls -la total 24 drwx------  2 test test 4096 Nov  5 14:51 . drwxr-xr-x. 6 root    root    4096 Nov  5 14:44 .. -rw-------  1 test test   21 Nov  5 14:45 .bash_history -rw-r--r--  1 test test   18 Nov  5 14:51 .bash_logout -rw-r--r--  1 test test  176 Nov  5 14:51 .bash_profile -rw-r--r--  1 test test  124 Nov  5 14:51 .bashrc -bash-4.1$ logout [root@xxxx ~]# su - test [test@xxxx ~]$ 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

搞定了

posted @ 2018-07-06 20:00 长戟十三千 阅读(12) | 评论 (0)编辑 收藏

一般察看函数运行时堆栈的方法是使用GDB之类的外部调试器,但是,有些时候为了分析程序的BUG,(主要针对长时间运行程序的分析),在程序出错时打印出函数的调用堆栈是非常有用的。

在头文件"execinfo.h"中声明了三个函数用于获取当前线程的函数调用堆栈

Function: int backtrace(void **buffer,int size)

该函数用与获取当前线程的调用堆栈,获取的信息将会被存放在buffer中,它是一个指针列表。参数 size 用来指定buffer中可以保存多少个void* 元素。函数返回值是实际获取的指针个数,最大不超过size大小在buffer中的指针实际是从堆栈中获取的返回地址,每一个堆栈框架有一个返回地址,注意某些编译器的优化选项对获取正确的调用堆栈有干扰,另外内联函数没有堆栈框架;删除框架指针也会使无法正确解析堆栈内容。

Function: char ** backtrace_symbols (void *const *buffer, int size)

backtrace_symbols
将从backtrace函数获取的信息转化为一个字符串数组. 参数buffer应该是从backtrace函数获取的数组指针,size是该数组中的元素个数(backtrace的返回值)。函数返回值是一个指向字符串数组的指针,它的大小同buffer相同.每个字符串包含了一个相对于buffer中对应元素的可打印信息.它包括函数名,函数的偏移地址,和实际的返回地址。
现在,只有使用ELF二进制格式的程序和苦衷才能获取函数名称和偏移地址.在其他系统,只有16进制的返回地址能被获取.另外,你可能需要传递相应的标志给链接器,以能支持函数名功能(比如,在使用GNU ld的系统中,你需要传递(-rdynamic))。
该函数的返回值是通过malloc函数申请的空间,因此调用这必须使用free函数来释放指针
.
注意:如果不能为字符串获取足够的空间函数的返回值将会为
NULL

Function:void backtrace_symbols_fd (void *const *buffer, int size, int fd)

backtrace_symbols_fd与backtrace_symbols 函数具有相同的功能,不同的是它不会给调用者返回字符串数组,而是将结果写入文件描述符为fd的文件中,每个函数对应一行.它不需要调用malloc函数,因此适用于有可能调用该函数会失败的情况。

 

下面是一个使用backtrace捕获异常并打印函数调用堆栈的例子:

 

复制代码
#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <execinfo.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <unistd.h>  #define PRINT_DEBUG  static void print_reason(int sig) {     void *array[10];     size_t size;     size = backtrace(array, 10); #ifdef PRINT_DEBUG     char **strings;     int i;     strings = backtrace_symbols(array, size);     printf("Obtained %d stack frames.\n", size);     for (i = 0; i < size; i++)         printf("%s\n", strings[i]);     free(strings);      char cmd[64] = "addr2line -C -f -e ";     char* prog = cmd + strlen(cmd);     readlink("/proc/self/exe", prog, sizeof(cmd) - strlen(cmd) - 1);// 获取进程的完整路径      FILE* fp = popen(cmd, "w");     if (fp != NULL)     {         for (i = 0; i < size; ++i)         {             fprintf(fp, "%p\n", array[i]);         }         pclose(fp);     } #else     int fd = open("err.log", O_CREAT | O_WRONLY);     backtrace_symbols_fd(array, size, fd);     close(fd); #endif     exit(0); } void die() {     char *test1;     char *test2;     char *test3;     char *test4 = NULL;     strcpy(test4, "ab"); } void test1() {     die(); } int main(int argc, char **argv) {     struct sigaction myAction;     myAction.sa_handler = print_reason;     sigemptyset(&myAction.sa_mask);     myAction.sa_flags = SA_RESTART | SA_SIGINFO;     sigaction(SIGSEGV, &myAction, NULL); // 无效内存引用     sigaction(SIGABRT, &myAction, NULL); // 异常终止     test1(); }
复制代码

 

 

我本机测试打印出的信息如下:

复制代码
Obtained 7 stack frames. /root/workspace/test/Debug/test(__gxx_personality_v0+0x12d) [0x80486c1] [0x71b440] /root/workspace/test/Debug/test(__gxx_personality_v0+0x2ac) [0x8048840] /root/workspace/test/Debug/test(__gxx_personality_v0+0x2c0) [0x8048854] /root/workspace/test/Debug/test(__gxx_personality_v0+0x339) [0x80488cd] /lib/libc.so.6(__libc_start_main+0xdc) [0xbf3e9c] /root/workspace/test/Debug/test(__gxx_personality_v0+0x5d) [0x80485f1] print_reason /root/workspace/test/Debug/../main.cpp:15 ?? ??:0 die() /root/workspace/test/Debug/../main.cpp:51 test1() /root/workspace/test/Debug/../main.cpp:56 main /root/workspace/test/Debug/../main.cpp:65 ?? ??:0 _start ??:0
posted @ 2018-06-29 17:03 长戟十三千 阅读(24) | 评论 (0)编辑 收藏

一、背景

系统管理员经常需要SSH 或者telent 远程登录到Linux 服务器,经常运行一些需要很长时间才能完成的任务,比如系统备份、ftp 传输等等。通常情况下我们都是为每一个这样的任务开一个远程终端窗口,因为它们执行的时间太长了。必须等待它们执行完毕,在此期间不能关掉窗口或者断开连接,否则这个任务就会被杀掉,一切半途而废了。

二、简介

GNU Screen是一款由GNU计划开发的用于命令行终端切换的自由软件。用户可以通过该软件同时连接多个本地或远程的命令行会话,并在其间自由切换。

GNU Screen可以看作是窗口管理器的命令行界面版本。它提供了统一的管理多个会话的界面和相应的功能。

  • 会话恢复
只要Screen本身没有终止,在其内部运行的会话都可以恢复。这一点对于远程登录的用户特别有用——即使网络连接中断,用户也不会失去对已经打开的命令行会话的控制。只要再次登录到主机上执行screen -r就可以恢复会话的运行。同样在暂时离开的时候,也可以执行分离命令detach,在保证里面的程序正常运行的情况下让Screen挂起(切换到后台)。这一点和图形界面下的VNC很相似。
  • 多窗口
在Screen环境下,所有的会话都独立的运行,并拥有各自的编号、输入、输出和窗口缓存。用户可以通过快捷键在不同的窗口下切换,并可以自由的重定向各个窗口的输入和输出。Screen实现了基本的文本操作,如复制粘贴等;还提供了类似滚动条的功能,可以查看窗口状况的历史记录。窗口还可以被分区和命名,还可以监视后台窗口的活动。
  • 会话共享
Screen可以让一个或多个用户从不同终端多次登录一个会话,并共享会话的所有特性(比如可以看到完全相同的输出)。它同时提供了窗口访问权限的机制,可以对窗口进行密码保护。

GNU's Screen 官方站点:http://www.gnu.org/software/screen/

三、语法

# screen [-AmRvx -ls -wipe][-d <作业名称>][-h <行数>][-r <作业名称>][-s ][-S <作业名称>]

参数说明

-A  将所有的视窗都调整为目前终端机的大小。
-d <作业名称>  将指定的screen作业离线。
-h <行数>  指定视窗的缓冲区行数。
-m  即使目前已在作业中的screen作业,仍强制建立新的screen作业。
-r <作业名称>  恢复离线的screen作业。
-R  先试图恢复离线的作业。若找不到离线的作业,即建立新的screen作业。
-s  指定建立新视窗时,所要执行的shell。
-S <作业名称>  指定screen作业的名称。
-v  显示版本信息。
-x  恢复之前离线的screen作业。
-ls或--list  显示目前所有的screen作业。
-wipe  检查目前所有的screen作业,并删除已经无法使用的screen作业。

四、常用screen参数

screen -S yourname -> 新建一个叫yourname的session
screen -ls -> 列出当前所有的session
screen -r yourname -> 回到yourname这个session
screen -d yourname -> 远程detach某个session
screen -d -r yourname -> 结束当前session并回到yourname这个session

在每个screen session 下,所有命令都以 ctrl+a(C-a) 开始。
C-a ? -> 显示所有键绑定信息
C-a c -> 创建一个新的运行shell的窗口并切换到该窗口
C-a n -> Next,切换到下一个 window 
C-a p -> Previous,切换到前一个 window 
C-a 0..9 -> 切换到第 0..9 个 window
Ctrl+a [Space] -> 由视窗0循序切换到视窗9
C-a C-a -> 在两个最近使用的 window 间切换 
C-a x -> 锁住当前的 window,需用用户密码解锁
C-a d -> detach,暂时离开当前session,将目前的 screen session (可能含有多个 windows) 丢到后台执行,并会回到还没进 screen 时的状态,此时在 screen session 里,每个 window 内运行的 process (无论是前台/后台)都在继续执行,即使 logout 也不影响。 
C-a z -> 把当前session放到后台执行,用 shell 的 fg 命令则可回去。
C-a w -> 显示所有窗口列表
C-a t -> Time,显示当前时间,和系统的 load 
C-a k -> kill window,强行关闭当前的 window
C-a [ -> 进入 copy mode,在 copy mode 下可以回滚、搜索、复制就像用使用 vi 一样
    C-b Backward,PageUp 
    C-f Forward,PageDown 
    H(大写) High,将光标移至左上角 
    L Low,将光标移至左下角 
    0 移到行首 
    $ 行末 
    w forward one word,以字为单位往前移 
    b backward one word,以字为单位往后移 
    Space 第一次按为标记区起点,第二次按为终点 
    Esc 结束 copy mode 
C-a ] -> Paste,把刚刚在 copy mode 选定的内容贴上

五、使用 screen

5.1 安装screen

流行的Linux发行版(例如Red Hat Enterprise Linux)通常会自带screen实用程序,如果没有的话,可以从GNU screen的官方网站下载。

[root@TS-DEV ~]# yum install screen [root@TS-DEV ~]# rpm -qa|grep screen screen-4.0.3-4.el5 [root@TS-DEV ~]#

5.2 创建一个新的窗口

安装完成后,直接敲命令screen就可以启动它。但是这样启动的screen会话没有名字,实践上推荐为每个screen会话取一个名字,方便分辨:

[root@TS-DEV ~]# screen -S david 

screen启动后,会创建第一个窗口,也就是窗口No. 0,并在其中打开一个系统默认的shell,一般都会是bash。所以你敲入命令screen之后,会立刻又返回到命令提示符,仿佛什么也没有发生似的,其实你已经进入Screen的世界了。当然,也可以在screen命令之后加入你喜欢的参数,使之直接打开你指定的程序,例如:

[root@TS-DEV ~]# screen vi david.txt

screen创建一个执行vi david.txt的单窗口会话,退出vi 将退出该窗口/会话。

5.3 查看窗口和窗口名称

打开多个窗口后,可以使用快捷键C-a w列出当前所有窗口。如果使用文本终端,这个列表会列在屏幕左下角,如果使用X环境下的终端模拟器,这个列表会列在标题栏里。窗口列表的样子一般是这样:

0$ bash  1-$ bash  2*$ bash  

这个例子中我开启了三个窗口,其中*号表示当前位于窗口2,-号表示上一次切换窗口时位于窗口1。

Screen默认会为窗口命名为编号和窗口中运行程序名的组合,上面的例子中窗口都是默认名字。练习了上面查看窗口的方法,你可能就希望各个窗口可以有不同的名字以方便区分了。可以使用快捷键C-a A来为当前窗口重命名,按下快捷键后,Screen会允许你为当前窗口输入新的名字,回车确认。

5.4 会话分离与恢复

你可以不中断screen窗口中程序的运行而暂时断开(detach)screen会话,并在随后时间重新连接(attach)该会话,重新控制各窗口中运行的程序。例如,我们打开一个screen窗口编辑/tmp/david.txt文件:

[root@TS-DEV ~]# screen vi /tmp/david.txt

之后我们想暂时退出做点别的事情,比如出去散散步,那么在screen窗口键入C-a d,Screen会给出detached提示:

暂时中断会话

半个小时之后回来了,找到该screen会话:

[root@TS-DEV ~]# screen -ls

重新连接会话:

[root@TS-DEV ~]# screen -r 12865

一切都在。

当然,如果你在另一台机器上没有分离一个Screen会话,就无从恢复会话了。

这时可以使用下面命令强制将这个会话从它所在的终端分离,转移到新的终端上来:

5.5 清除dead 会话

如果由于某种原因其中一个会话死掉了(例如人为杀掉该会话),这时screen -list会显示该会话为dead状态。使用screen -wipe命令清除该会话:

5.6 关闭或杀死窗口

正常情况下,当你退出一个窗口中最后一个程序(通常是bash)后,这个窗口就关闭了。另一个关闭窗口的方法是使用C-a k,这个快捷键杀死当前的窗口,同时也将杀死这个窗口中正在运行的进程。

如果一个Screen会话中最后一个窗口被关闭了,那么整个Screen会话也就退出了,screen进程会被终止。

除了依次退出/杀死当前Screen会话中所有窗口这种方法之外,还可以使用快捷键C-a :,然后输入quit命令退出Screen会话。需要注意的是,这样退出会杀死所有窗口并退出其中运行的所有程序。其实C-a :这个快捷键允许用户直接输入的命令有很多,包括分屏可以输入split等,这也是实现Screen功能的一个途径,不过个人认为还是快捷键比较方便些。

六、screen 高级应用 

6.1 会话共享

还有一种比较好玩的会话恢复,可以实现会话共享。假设你在和朋友在不同地点以相同用户登录一台机器,然后你创建一个screen会话,你朋友可以在他的终端上命令:

[root@TS-DEV ~]# screen -x

这个命令会将你朋友的终端Attach到你的Screen会话上,并且你的终端不会被Detach。这样你就可以和朋友共享同一个会话了,如果你们当前又处于同一个窗口,那就相当于坐在同一个显示器前面,你的操作会同步演示给你朋友,你朋友的操作也会同步演示给你。当然,如果你们切换到这个会话的不同窗口中去,那还是可以分别进行不同的操作的。

6.2 会话锁定与解锁

Screen允许使用快捷键C-a s锁定会话。锁定以后,再进行任何输入屏幕都不会再有反应了。但是要注意虽然屏幕上看不到反应,但你的输入都会被Screen中的进程接收到。快捷键C-a q可以解锁一个会话。

也可以使用C-a x锁定会话,不同的是这样锁定之后,会话会被Screen所属用户的密码保护,需要输入密码才能继续访问这个会话。

6.3 发送命令到screen会话

在Screen会话之外,可以通过screen命令操作一个Screen会话,这也为使用Screen作为脚本程序增加了便利。关于Screen在脚本中的应用超出了入门的范围,这里只看一个例子,体会一下在会话之外对Screen的操作:

[root@TS-DEV ~]# screen -S sandy -X screen ping www.baidu.com

这个命令在一个叫做sandy的screen会话中创建一个新窗口,并在其中运行ping命令。

6.4 屏幕分割

现在显示器那么大,将一个屏幕分割成不同区域显示不同的Screen窗口显然是个很酷的事情。可以使用快捷键C-a S将显示器水平分割,Screen 4.00.03版本以后,也支持垂直分屏,快捷键是C-a |。分屏以后,可以使用C-a <tab>在各个区块间切换,每一区块上都可以创建窗口并在其中运行进程。

可以用C-a X快捷键关闭当前焦点所在的屏幕区块,也可以用C-a Q关闭除当前区块之外其他的所有区块。关闭的区块中的窗口并不会关闭,还可以通过窗口切换找到它。

6.5 C/P模式和操作

screen的另一个很强大的功能就是可以在不同窗口之间进行复制粘贴了。使用快捷键C-a <Esc>或者C-a [可以进入copy/paste模式,这个模式下可以像在vi中一样移动光标,并可以使用空格键设置标记。其实在这个模式下有很多类似vi的操作,譬如使用/进行搜索,使用y快速标记一行,使用w快速标记一个单词等。关于C/P模式下的高级操作,其文档的这一部分有比较详细的说明。

一般情况下,可以移动光标到指定位置,按下空格设置一个开头标记,然后移动光标到结尾位置,按下空格设置第二个标记,同时会将两个标记之间的部分储存在copy/paste buffer中,并退出copy/paste模式。在正常模式下,可以使用快捷键C-a ]将储存在buffer中的内容粘贴到当前窗口。

6.6 更多screen功能

同大多数UNIX程序一样,GNU Screen提供了丰富强大的定制功能。你可以在Screen的默认两级配置文件/etc/screenrc和$HOME/.screenrc中指定更多,例如设定screen选项,定制绑定键,设定screen会话自启动窗口,启用多用户模式,定制用户访问权限控制等等。如果你愿意的话,也可以自己指定screen配置文件。

以多用户功能为例,screen默认是以单用户模式运行的,你需要在配置文件中指定multiuser on 来打开多用户模式,通过acl*(acladd,acldel,aclchg...)命令,你可以灵活配置其他用户访问你的screen会话。更多配置文件内容请参考screen的man页。

posted @ 2018-06-28 20:12 长戟十三千 阅读(7) | 评论 (0)编辑 收藏

如何判断一个点是否在多边形内部?

(1)面积和判别法:判断目标点与多边形的每条边组成的三角形面积和是否等于该多边形,相等则在多边形内部。

(2)夹角和判别法:判断目标点与所有边的夹角和是否为360度,为360度则在多边形内部。

(3)引射线法:从目标点出发引一条射线,看这条射线和多边形所有边的交点数目。如果有奇数个交点,则说明在内部,如果有偶数个交点,则说明在外部。

具体做法:将测试点的Y坐标与多边形的每一个点进行比较,会得到一个测试点所在的行与多边形边的交点的列表。在下图的这个例子中有8条边与测试点所在的行相交,而有6条边没有相交。如果测试点的两边点的个数都是奇数个则该测试点在多边形内,否则在多边形外。在这个例子中测试点的左边有5个交点,右边有三个交点,它们都是奇数,所以点在多边形内。

算法图解:

关于这个算法的具体的更多图形例子:http://alienryderflex.com/polygon/

参考代码:

复制代码
int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy) {   int i, j, c = 0;   for (i = 0, j = nvert-1; i < nvert; j = i++)    {     if ( ((verty[i]>testy) != (verty[j]>testy)) &&      (testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )        c = !c;   }   return c; }
复制代码

来自一个polygon的内部实现:

复制代码
      public bool IsInside(PointLatLng p)       {          int count = Points.Count;           if(count < 3)          {             return false;          }           bool result = false;           for(int i = 0, j = count - 1; i < count; i++)          {             var p1 = Points[i];             var p2 = Points[j];              if(p1.Lat < p.Lat && p2.Lat >= p.Lat || p2.Lat < p.Lat && p1.Lat >= p.Lat)             {                if(p1.Lng + (p.Lat - p1.Lat) / (p2.Lat - p1.Lat) * (p2.Lng - p1.Lng) < p.Lng)                {                   result = !result;                }             }             j = i;          }          return result;       }
复制代码

特殊情况:要检测的点在多变形的一条边上,射线法判断的结果是不确定的,需要特殊处理(If the test point is on the border of the polygon, this algorithm will deliver unpredictable results)。

计算一个多边形的面积(area of a polygon):

复制代码
        private static double SignedPolygonArea(List<PointLatLng> points)         {             // Add the first point to the end.             int pointsCount = points.Count;             PointLatLng[] pts = new PointLatLng[pointsCount + 1];             points.CopyTo(pts, 0);             pts[pointsCount] = points[0];              for (int i = 0; i < pointsCount + 1; ++i)             {                 pts[i].Lat = pts[i].Lat * (System.Math.PI * 6378137 / 180);                 pts[i].Lng = pts[i].Lng * (System.Math.PI * 6378137 / 180);             }              // Get the areas.             double area = 0;             for (int i = 0; i < pointsCount; i++)             {                 area += (pts[i + 1].Lat - pts[i].Lat) * (pts[i + 1].Lng + pts[i].Lng) / 2;             }              // Return the result.             return area;         }          /// <summary>         /// Get the area of a polygon         /// </summary>         /// <param name="points"></param>         /// <returns></returns>         public static double GetPolygonArea(List<PointLatLng> points)         {             // Return the absolute value of the signed area.             // The signed area is negative if the polygon is oriented clockwise.             return Math.Abs(SignedPolygonArea(points));         }
复制代码

 

 

posted @ 2018-06-22 11:03 长戟十三千 阅读(14) | 评论 (0)编辑 收藏

ASANAddress-Sanitizier早先是LLVM中的特性,后被加入GCC 4.8,在GCC 4.9后加入对ARM平台的支持。因此GCC 4.8以上版本使用ASAN时不需要安装第三方库,通过在编译时指定编译CFLAGS即可打开开关。

1、编译选项

1.1 Gcc编译选项

# -fsanitize=address:开启内存越界检测

# -fsanitize-recover=address:一般后台程序为保证稳定性,不能遇到错误就简单退出,而是继续运行,采用该选项支持内存出错之后程序继续运行,需要叠加设置ASAN_OPTIONS=halt_on_error=0才会生效;若未设置此选项,则内存出错即报错退出

ASAN_CFLAGS += -fsanitize=address -fsanitize-recover=address

 

# -fno-stack-protector:去使能栈溢出保护

# -fno-omit-frame-pointer:去使能栈溢出保护

# -fno-var-tracking:默认选项为-fvar-tracking,会导致运行非常慢

# -g1:表示最小调试信息,通常debug版本用-g-g2

ASAN_CFLAGS += -fno-stack-protector -fno-omit-frame-pointer -fno-var-tracking -g1

1.2 Ld链接选项

ASAN_LDFLAGS += -fsanitize=address -g1

如果使用gcc链接,此处可忽略。

2ASAN运行选项

2.1 ASAN_OPTIONS设置

ASAN_OPTIONSAddress-Sanitizier的运行选项环境变量。

# halt_on_error=0:检测内存错误后继续运行

# detect_leaks=1:使能内存泄露检测

# malloc_context_size=15:内存错误发生时,显示的调用栈层数为15

# log_path=/home/xos/asan.log:内存检查问题日志存放文件路径

# suppressions=$SUPP_FILE:屏蔽打印某些内存错误

export ASAN_OPTIONS=halt_on_error=0:use_sigaltstack=0:detect_leaks=1:malloc_context_size=15:log_path=/home/xos/asan.log:suppressions=$SUPP_FILE

 

除了上述常用选项,以下还有一些选项可根据实际需要添加:

# detect_stack_use_after_return=1:检查访问指向已被释放的栈空间

# handle_segv=1:处理段错误;也可以添加handle_sigill=1处理SIGILL信号

# quarantine_size=4194304:内存cache可缓存free内存大小4M

ASAN_OPTIONS=${ASAN_OPTIONS}:verbosity=0:handle_segv=1:allow_user_segv_handler=1:detect_stack_use_after_return=1:fast_unwind_on_fatal=1:fast_unwind_on_check=1:fast_unwind_on_malloc=1:quarantine_size=4194304

2.2 LSAN_OPTIONS设置

LSAN_OPTIONSLeakSanitizier运行选项的环境变量,而LeakSanitizierASAN的内存泄漏检测模块,常用运行选项有:

# exitcode=0:设置内存泄露退出码为0,默认情况内存泄露退出码0x16

# use_unaligned=44字节对齐

export LSAN_OPTIONS=exitcode=0:use_unaligned=4

3、总结

实际开发环境中,可能存在gcc版本低,使用asan做内存检查时,需要链接libasan.so库的情况。其次,平台软件通常都会内部实现一套内存操作接口,为使用asan工具,需要替换成glibc提供的接口。此时,可以通过LD_PRELOAD环境变量解决这类问题。

export LD_PRELOAD= libasan.so.2:libprelib.so   #vos_malloc --> malloc



ps:
1、安装LLVM 3.1以上版本

2、编译参数附加

-fsanitize=address

3、设置环境变量参数

export ASAN_SYMBOLIZER_PATH=/usr/local/bin/llvm-symbolizer

export ASAN_OPTIONS=symbolize=1

4、运行程序,如果出错,addressSanitizer会给出详细的报告。

posted @ 2018-06-14 15:46 长戟十三千 阅读(104) | 评论 (0)编辑 收藏
#include<stdio.h>
#include<pthread.h>
#include<signal.h>
#include<setjmp.h>
#include<errno.h>

static sigjmp_buf env;
pthread_t thread;

void alarm_handler(int sig){
        siglongjmp(env, -1);
        printf("alarm_handler\n");
        return;
}

void threadtest(){
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGALRM);
    sigprocmask(SIG_UNBLOCK, &set, NULL);
    struct sigaction act,oldact;
    act.sa_handler = alarm_handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags |= SA_INTERRUPT;
    sigaction(SIGALRM, &act, &oldact);
    if(sigsetjmp(env, 1) != 0){
        printf("sigsetjmp\n");
        alarm(0);
        sigaction(SIGALRM, &oldact, NULL);
        sigprocmask(SIG_BLOCK, &set, NULL);  //还不行就使用pthread_sigmask(SIG_UNBLOCK, &set, NULL);
        return;
    }
    alarm(2);
    printf("sleep before\n");
    int i = 1;
    while(i<= 10) {
        printf("i = %d\n",i++);
        sleep(1);
    }
    printf("sleep end\n");
    alarm(0);
    sigaction(SIGALRM, &oldact, NULL);
    sigprocmask(SIG_BLOCK, &set, NULL);  //还不行就使用pthread_sigmask(SIG_UNBLOCK, &set, NULL);
    return;
}

int main(){
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGALRM);
    sigprocmask(SIG_BLOCK, &set, NULL);
    int err = 1;
    threadtest();  //函数调用
   while(err <= 3) {
         printf("err = %d\n",err++);
         sleep(1);
    }
    putchar('\n');
        
    pthread_create(&thread,NULL,(void *)threadtest,NULL);   //用线程的方式
   err = 1;
    while(err <= 5) {
        printf("err = %d\n",err++);
        sleep(1);
    }
    pthread_join(thread,NULL);
}
posted @ 2018-06-14 15:27 长戟十三千 阅读(11) | 评论 (0)编辑 收藏
仅列出标题  下一页