Linux系统开发那点事儿 分享经验得牛人力作!(获奖名单已公布-2014-5-28)
获奖名单已公布,详情请看:http://bbs.chinaunix.net/thread-4140163-1-1.html话题背景:
Linux系统编程想必大家都已不陌生,高手众多,不过有些坎,即使高手也难逃一劫,前仆后继的被绊一跤。“系统编程”是指编写系统软件,其代码在底层运行,直接跟内核和核心系统库对话。比如说Linux系统调用和底层函数说明,如C库定义的函数。作为基础,系统程序员需要对Linux文件系统、I/O、缓存、进程、内存都有了解,要想成为大家则需精通。大家可以聊聊自己在开发过程中遇见的各种诡异的情景,奇葩的错误,比如api的使用死角,例如syslog传入的数据没有对%进行转义,内存爆栈,网络洪水,自己把自己DDOS打死;等等各种印象深刻的事情。
今日话题:
1. 系统开发中遇见的那些头疼的问题
2. 系统开发过程中的收获
3. 如何做好Linux 系统开发
活动时间:
2014-4-8至2014-5-15
活动奖励:
我们将会选择几位突出的网友赠送一本常读常新的书籍《Linux系统编程》第二版,作者是大名鼎鼎Robert Love
这个作者可是非常有名,Google的高级工程师,写的书质量极高,书虽然不厚,内容却都是干货
Linux系统编程经典之作,根据Linux内核3.0更新 !
Linux程序设计方面的传奇人物Robert Love力作 !
奖品简介:
Linux系统编程(第2版)
http://images.china-pub.com/ebook3765001-3770000/3769917/zcover.jpg
作者: (美)Robert Love
译者: 祝洪凯 李妹芳 付途
出版社:人民邮电出版社
ISBN:9787115346353
上架时间:2014-4-18
出版日期:2014 年4月
开本:16开
页码:420
图书样张:
(样张文件需要两个都要下载解压才能打开)
问题倒多,可惜大部分是自己的问题 我遇到的这个问题其实应该不算个问题,但在我刚开始学多线程编程的时候却困扰了我很久,在网上也没找到答案,或者说没有直接的答案,后来是自己去读了部分nptl源代码后才明白原因,虽然费时很多,但也收获良多。
问题很简单,就是关于线程取消的操作,在某种情况下,线程不管怎样都不能退出,问题肯定是出在锁上,但始终找不到死锁的地方,先帖段代码:#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t lock;
pthread_cond_t cond;
void thrd_cleanup()
{
printf("thread canceled\n");
pthread_mutex_unlock(&lock);
}
void thrd_func()
{
pthread_cleanup_push(thrd_cleanup, NULL);
printf("thread: enter\n");
pthread_mutex_lock(&lock);
pthread_cond_wait(&cond, &lock);
pthread_mutex_unlock(&lock);
pthread_cleanup_pop(0);
printf("thread: exit\n");
}
int main(int argc, char *argv[])
{
pthread_t tid;
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&cond, NULL);
for (int i = 0; i < 4; ++i) {
int ret = pthread_create(&tid, NULL, thrd_func, NULL);
if (ret) {
perror("pthread_create");
}
}
sleep(3);
pthread_mutex_lock(&lock);
for (int i = 0; i < 4; ++i) {
printf("before cancel\n");
pthread_cancel(tid);
pthread_join(tid, NULL);
printf("after cancel\n");
}
pthread_mutex_unlock(&lock);
sleep(6);
return 0;
}上面代码得到的输出为thread: enter
thread: enter
thread: enter
thread: enter
before cancel可见在第一个线程退出的时候出了问题,一开始就几乎可以肯定是锁这出了问题,可一直找不到原因,attach该进程,得到的结果为(gdb) bt
#00xb772f424 in __kernel_vsyscall ()
#10xb7707e1c in pthread_join () from /lib/i386-linux-gnu/libpthread.so.0
#20x080489f4 in main (argc=1, argv=0xbfe68a24) at main.c:67可见,程序在调用pthread_join后阻塞了,再查看当前进程中的线程:(gdb) info threads
Id Target Id Frame
4 Thread 0xb6d52b40 (LWP 5658) "foo" 0xb772f424 in __kernel_vsyscall ()
3 Thread 0xb6551b40 (LWP 5659) "foo" 0xb772f424 in __kernel_vsyscall ()
2 Thread 0xb5d50b40 (LWP 5660) "foo" 0xb772f424 in __kernel_vsyscall ()
* 1 Thread 0xb75546c0 (LWP 5656) "foo" 0xb772f424 in __kernel_vsyscall ()显示已经有一个线程成功退出,而查看进程的/proc文件系统信息得到的却是:$ls /proc/5656/task
56565657565856595660这却说明刚才的那个线程没有完全退出,当时我觉得这是相当诡异的,所谓百思不得其解啊,最后经过分析nptl关于pthread_cancel操作的源码后,终于找到了原因:
我们在进入线程的时候注册了线程清理理函数,随后进入等待状态,注意这时候主线程已经持有锁了,并调用pthread_cancel和pthread_join,这个时候nptl的实现中需要再次持有该锁,这时候问题就出现了,主线程持有锁并等待pthread_join的结束,而nptl库需要先拿到锁才能返回,这就永远不会结束,导致上面的问题。
经过这个问题之后,觉得多线程编程真是个头疼的问题,稍有不甚就会出现各种诡异的问题,尤其对于初学者,经验不足,解决起这些问题是费时费力又不一定有效果。
支持活动,好活动探讨linux开源系统。 1. 系统开发中遇见的那些头疼的问题
多线程, 用pthread的时候, 栈开小了, 出了错是panic 吧.
tcp/ip 数据同步出问题, x86到power时, 映射数据会有大小端转换
2. 系统开发过程中的收获
解决方案没把握时, 一定要写个demo来验证一下. 最大的坑就是那个著名的 a.out,一定要./a.out才可以执行。有多少初学者, gcc hello.c一次写对编译成功并执行成功的? mmap失败返回的不是想当然的NULL,而是MAP_FAILED(-1):mrgreen: 回复 3# 阿注哥
分析NPTL源码解决问题,很强大啊!
个人使用多线程时恪守两个原则:
1. “thread is evil”,能不用就不用。Linux/UNIX下,多线程比多进程的优势并没有教科书理论阐释的那么美好,不过多线程确实可以简化共享数据结构的实现,看看多进程五花八门的IPC就知道了。
2. 使用简单的核心API,少用高大上。理解mutex/condition variable/semaphore API就可以解决多数问题,当想用push/pop/cancel等等偏门API时,反省自己的代码架构,通常可以避免之。
回复 8# timespace
linux的线程用轻量进程实现,实则区别不大,记得看过一篇文章,详细介绍其区别,也说了没特别的必要性就尽量避免!那么花了我好多时间才搞明白,算是印象深刻的一次经历了。 做C语言开发有一段时间了,我的一些经验分享给大家:
1 C就是C,不要在C中实现try ... catch, 如果实在避不开,用一下setjmp longjunp,不建议大量使用,多用if做判断更好
2 C就是C,不要在C中试图实现类似C++/Java等语言中的类,C吗?简单点更好
3 内存管理,如果不能简单到每次申请大小都是固定长度字节的内存,那就别自己管理内存了,有更好的工具可以使用,比如:Google Performance Tools