一般察看函数运行时堆栈的方法是使用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 长戟十三千 阅读(1570) |
评论 (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 长戟十三千 阅读(293) |
评论 (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 长戟十三千 阅读(911) |
评论 (0) |
编辑 收藏
ASAN(Address-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链接,此处可忽略。
2、ASAN运行选项
2.1 ASAN_OPTIONS设置
ASAN_OPTIONS是Address-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_OPTIONS是LeakSanitizier运行选项的环境变量,而LeakSanitizier是ASAN的内存泄漏检测模块,常用运行选项有:
# exitcode=0:设置内存泄露退出码为0,默认情况内存泄露退出码0x16
# use_unaligned=4:4字节对齐
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 长戟十三千 阅读(21521) |
评论 (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 长戟十三千 阅读(426) |
评论 (0) |
编辑 收藏
摘要: 《守望先锋》架构设计与网络同步Overwatch Gameplay Architecture and NetcodeTimothy FordLead Gameplay EngineerBlizzard Entertainment翻译:kevinan 在GDC2017【Overwatch Gameplay Architecture andNetcode 】的分享会上,来自暴雪的T...
阅读全文
posted @
2018-06-12 16:52 长戟十三千 阅读(474) |
评论 (0) |
编辑 收藏
环境:centos6.3
1. 要使用distcc当然需要先去安装。这里使用官方源码编译安装。 下载地址:https://code.google.com/p/distcc/downloads/list
这里选择需要下载的内容,我选择的是distcc-3.2rc1.tar.bz2
2. 编译distcc源码需要先安装python支持, 在centos中使用 sudo yum install python-devel 其他linux可以参照
3. 安装好了python后,解压distcc源码:
进入distcc-3.2rc1.tar.bz2 : cd distcc-3.2rc1
执行:./autogen.sh ---->./configure ---> make -----> make install
4. 至此distcc就算安装完成,安装结束后还需要开启distccd这个守护进程。为方便每次自启动该守护进程,可以将其添加到开机自启动项
在centos中 可以到 /etc/rc.local 中添加
其中 --user 表明使用nobody这个用户身份 --allow 表明那一些ip允许访问,这里 192.168.168.0/8 表明192.168.168.1—192.168.168.254这个区间的IP可以使用该机器的distcc
5. distcc相关的环境变量:
distcc需要指明他可以使用的编译阵列。这些环境变量可以存放在~/.bashrc. 使用vim打开该文件:vim ~/.bashrc
DISTCC_HOSTS 指明那些机器安装了distcc 且开启了distccd。编译过程中可以使用这些机器进行编译
DISTCC_LOG 表明distcc相关日志
6. 重启centos
PS:在其他DISTCC_HOSTS列表中的机器上重复1-6步骤。 注意DISTCC_HOSTS 中的列表项用空格隔开。
7. 进入你要进行编译的文件目录:
-j16 可以同时编译多个, CXX=distcc 表明c++文件使用distcc来进行编译 对饮C文件 可以使用 CC=distcc
然后就开始编译了,在编译过程中可以使用命令 distccmon-text 2 来查看编译过程中使用了那一些机器
可以看到有很多文件在其他机器上编译。
就我们项目而言,之前单个机器上编译gameserver差不多需要20分钟,在部署之后,使用distcc编译缩短在6分钟左右。 效果不错。
1、需要 python 头文件,下载安装。
2、下载安装 distcc-3.1.tar.bz2。
3、export DISTCC_HOSTS='localhost 10.10.13.162‘ //添加所有欲分发的distcc服务器IP列表,ip应按各服务器性能由好到差排列。
export DISTCC_VERBOSE=1 //给出调试信息
export DISTCC_LOG=”/root/disstcc.log” //编译出错时可以查看日志,默认路径是 /var/log/messages
以上可以写入到 ~/.bash_profile 中,以便开机有效。
4、在每一台服务器上安装好 distcc 之后,先启动服务器 distccd --daemon --user nobody --allow 10.10.0.0/16 接收来自10.10网段的所有TCP连接,最好加入开机启动。(如果不加--user nobody则会提示:distccd[4596] (dcc_preferred_user) Warning: no such user as "distcc")
5、可以通过 distccmon-text 1 命令查看分布编译情况,1表示1秒。如果在 ./configure 时,加上了 --with-gnome or --with-gtk 选项,则还可以使用 distccmon-gnome 1 这个图形界面来查看。
6、可以和 ccache 配合 : time make -j12 CXX="ccache distcc",不过感觉同时使用 distcc 和 ccache 的效果跟只使用 distcc 的效果差不多。如果只有一台机器,就使用 ccache ,如果有多台机器就只使用 distcc 吧。
7、使用 dmucs 配合 distcc 解决分布式编译的负载均衡问题:
http://www.ibm.com/developerworks/cn/aix/library/0905_yangyi_distcc/
下面转自:http://blog.chinaunix.net/uid-20553497-id-3214404.html
distcc是一个分布式的编译工具,包含distccd和distcc。其中distccd是服务端,需要安装在远程协助编译的多台服务器上,而distcc是一个客户端,需要安装在分发编译任务的服务器上。centos可以直接在http://pkgs.repoforge.org/distcc/ 上下载2个RPM包:
distcc-2.18.3-2.el5.rf.x86_64.rpmdistcc-server-2.18.3-2.el5.rf.x86_64.rpm
test[1-5].inner.net是我的5台服务器,直接在5台服务器上都安装这2个包,然后同步一下5台服务器的配置文件
- # cat /etc/sysconfig/distccd
- ### See distcc(1) manual page for more information on these options.
- ###
- OPTIONS="--nice 5 --jobs 10 --port 3632 --allow 127.0.0.1 --allow 10.0.0.0/8 "
- #USER="distcc"
- ### Set this if don't want distccd to use gcc or g++ by accident.
- #DISTCCPATH="/usr/lib/distcc/bin"
红色部分是需要注意的,distcc默认使用的端口是3632,而distccd默认的端口是1234,这个搞得我查了很久才找到原因。
修改配置后对于每个服务器
- chkconfig --level 2345 distccd on
- service distccd restart
然后就可以使用了,以编译nginx为例
- export CC=distcc; ./configure
- export DISTCC_HOSTS="test1.inner.net .... test5.inner.net"
- make -j 20
这样就会向每台服务器分发出任务。
预处理工作其实还是在分发任务的机器上执行的,然后把预处理后的代码传输到远程服务器,编译成.o文件,再取回来链接生成可执行程序。
编译的时候参与编译的服务器上可以看到日志 tail /var/log/distccd.log
分发编译任务的机器上可以使用 distccmon-text 1查看编译任务的分发
posted @
2018-06-08 10:06 长戟十三千 阅读(2179) |
评论 (0) |
编辑 收藏
CentOS7系统自带的Python版本是Python2.7,如需使用Python3.6,需要自行安装Python3.6。
CentOS7安装Python3.6有两种方式:
- 使用Yum源安装Python3.6
- 使用Python3.6源文件安装
推荐使用CentOS7 Yum源安装Python3.6。
CentOS7使用Yum源安装Python3.6
IUS软件源中包含了Python3.6,可以使用IUS软件源安装Python3.6,查看如何安装使用IUS软件源
1)安装IUS软件源
#安装EPEL依赖 sudo yum install epel-release #安装IUS软件源 sudo yum install https://centos7.iuscommunity.org/ius-release.rpm
2)安装Python3.6
sudo yum install python36u
安装Python3完成后的shell命令为python3.6,为了使用方便,创建一个到python3的符号链接
sudo ln -s /bin/python3.6 /bin/python3
3)安装pip3
安装完成python36u并没有安装pip,安装pip
sudo yum install python36u-pip
安装pip完成后的shell命令为pip3.6,为了使用方便,创建一个到pip3的符号链接
sudo ln -s /bin/pip3.6 /bin/pip3
CentOS7使用源文件安装Python3.6
1)在安装Python3.6之前,先安装Python3.6需要的依赖:
sudo yum -y groupinstall development sudo yum -y install zlib-devel
2)运行如下命令安装Python3.6
wget https://www.python.org/ftp/python/3.6.0/Python-3.6.0.tar.xz tar xJf Python-3.6.0.tar.xz cd Python-3.6.0 sudo ./configure sudo make sudo make install
安装完成后,Python安装在了/usr/local
文件夹中,可运行文件/usr/local/bin
,库文件/usr/local/lib
。
posted @
2018-06-06 13:49 长戟十三千 阅读(412) |
评论 (0) |
编辑 收藏
由于安装与配置一个适合开发的vim环境比较复杂,本文将自己安装配置vim及其插件的过程进行记录,以便以后查看。希望也能对喜欢vim的同学提供一些帮助。
目的:在CentOS7上安装配置vim8.1,打造一个适合开发的编辑环境。
说明:相关配置文件可以在我的github中获取:
https://github.com/stevenzscn/vim_install
一、准备工作
1. 安装dircolors:
git clone https://github.com/seebi/dircolors-solarized.git
cd dircolors-solarized/
mv dircolors.ansi-dark ~/.dircolors
在bash_profile中添加:
export TERM=xterm-256color
if [ -x /usr/bin/dircolors ]; then
alias ls='ls --color=auto'
alias dir='dir --color=auto'
alias vdir='vdir --color=auto'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'
alias tree='tree -C'
fi
重新登录后,生效。
2. 安装依赖:
yum install libXt-devel gtk2-devel
yum -y install python-devel ruby ruby-devel perl perl-devel perl-ExtUtils-Embed
yum install ncurses-devel
yum install ctags
需要依赖python3:
下载Python-3.6.5.tgz
tar -zxv -f Python-3.6.5.tgz
cd Python-3.6.5
./configure --prefix=/usr/local/python3
make
sudo make install
3. 关闭SELinux
修改/etc/selinux/config 文件
将SELINUX=enforcing改为SELINUX=disabled
重启机器。
二、安装vim8.1
git clone https://github.com/vim/vim.git
cd vim
./configure --disable-selinux --enable-perlinterp=yes --enable-python3interp=yes --enable-rubyinterp=yes --enable-cscope --enable-gui=auto --with-features=huge --enable-multibyte --enable-xim --with-x --with-gnome --with-compiledby="Steven Zhang" --prefix=/usr/local/vim8
make
make install
到此vim8.1安装完成,查看version信息:
三、安装vim插件
下面将安装vim插件,使用vundle管理插件:
Plugin 'VundleVim/Vundle.vim'
Plugin 'altercation/vim-colors-solarized'
Plugin 'tomasr/molokai'
Plugin 'vim-scripts/phd'
Plugin 'vim-airline/vim-airline'
Plugin 'vim-airline/vim-airline-themes'
Plugin 'octol/vim-cpp-enhanced-highlight'
Plugin 'derekwyatt/vim-fswitch'
Plugin 'vim-scripts/a.vim'
Plugin 'kshenoy/vim-signature'
Plugin 'vim-scripts/BOOKMARKS--Mark-and-Highlight-Full-Lines'
Plugin 'majutsushi/tagbar'
Plugin 'vim-scripts/indexer.tar.gz'
Plugin 'vim-scripts/DfrankUtil'
Plugin 'vim-scripts/vimprj'
Plugin 'dyng/ctrlsf.vim'
Plugin 'scrooloose/nerdcommenter'
Plugin 'vim-scripts/DrawIt'
Plugin 'SirVer/ultisnips'
Plugin 'Valloric/YouCompleteMe'
Plugin 'rdnetto/YCM-Generator'
Plugin 'derekwyatt/vim-protodef'
Plugin 'scrooloose/nerdtree'
Plugin 'gcmt/wildfire.vim'
Plugin 'sjl/gundo.vim'
Plugin 'Lokaltog/vim-easymotion'
Plugin 'suan/vim-instant-markdown'
Plugin 'qpkorr/vim-bufkill'
Plugin 'skywind3000/asyncrun.vim'
下面是我的vim配置 .vimrc 可以在我的github获取。
1. 安装vundle
vundle会自动下载插件,除YouCompleteMe以外不需要额外的安装操作,YouCompleteMe的安装将在后面说明。
git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim
vundle会管理.vim下的插件。
打开vim,执行 :BundleInstall ,vundle将自动下载配置的插件。
有时会出现显示异常,比如NERDTree的分支箭头。一般在Linux GNome里是显示正常的,但是使用xshell等终端可能就显示异常,这时可以将分支显示修改成传统的“+ 、~” 符号。
查看.vim/bundle/nerdtree/plugin/NERD_tree.vim
看到 if !nerdtree#runningWindows() 判断后是出现显示异常的地方,可以去掉条件判断:
这样除了YouCompleteMe以外,都搞定了。
2. 安装YouCompleteMe
1) 安装cmake
cmake 2版本安装YCM会有问题,所以这里需要升级cmake。如果使用yum安装了2版本的,请先yum remove cmake 。
下载cmake-3.9.1.tar.gz,安装:
tar -zxv -f cmake-3.9.1.tar.gz
cd cmake-3.9.1/
./bootstrap && make && make install
2) 安装YouCompleteMe
cd .vim/bundle/YouCompleteMe
./install.sh --clang-completer
安装完成后,打开vim会显示python import ycm_core 找不到libclang.so.3.9
复制一份.ycm_extra_conf.py到用户目录下:
cp YouCompleteMe/third_party/ycmd/examples/.ycm_extra_conf.py ~/
.ycm_extra_conf.py是YCM的配置文件,可以根据自己的项目情况进行配置。
也可以使用YCM-Generator插件,根据项目去生成:
./config_gen.py PROJECT_DIRECTORY
或在vim中使用:YcmGenerateConfig
详细用法请查看YCM-Generator文档。
至此YCM安装完成,效果如下:
现在,vim8.1就安装配置完成了。上几张安装后的图:
posted @
2018-06-06 13:23 长戟十三千 阅读(2440) |
评论 (0) |
编辑 收藏
#define exit_if(r, ...) if(r) {printf(__VA_ARGS__); printf("%s:%d error no: %d error msg %s\n", __FILE__, __LINE__, errno, strerror(errno)); exit(1);}
posted @
2018-05-22 00:43 长戟十三千 阅读(200) |
评论 (0) |
编辑 收藏