unix编程学习路线图(转)

建议学习路径:

  首先先学学编辑器,vim, emacs什么的都行。
然后学make file文件,只要知道一点就行,这样就可以准备编程序了。

  然后看看《C程序设计语言》K&R,这样呢,基本上就可以进行一般的编程了,顺便找本数据结构的书来看。

  如果想学习UNIX/LINUX的编程,《APUE》绝对经典的教材,加深一下功底,学习《UNP》的第二卷。这样基本上系统方面的就可以掌握了。

  然后再看Douglus E. Comer的《用TCP/IP进行网际互连》第一卷,学习一下网络的知识,再看《UNP》的第一卷,不仅学习网络编程,而且对系统编程的一些常用的技巧就 很熟悉了,如果继续网络编程,建议看《TCP/IP进行网际互连》的第三卷,里面有很多关于应用协议telnet、ftp等协议的编程。
如果想写设备驱动程序,首先您的系统编程的接口比如文件、IPC等必须要熟知了,再学习《LDD》2。

  对于几本经典教材的评价:

  《The C Programing Language》K&R 经典的C语言程序设计教材,作者是C语言的发明者,教材内容深入浅出。虽然有点老,但是必备的一本手册,现在有时候我还常翻翻。篇幅比较小,但是每看一 遍,就有一遍的收获。另外也可用谭浩强的《C语言程序设计》代替。

  《Advanced Programing in Unix Envirement》 W.Richard Stevens:也是非常经典的书(废话,Stevens的书哪有不经典的!),虽然初学者就可以看,但是事实上它是《Unix Network Programing》的一本辅助资料。国内的翻译的《UNIX环境高级编程》的水平不怎么样,现在有影印版,直接读英文比读中文来得容易。

  《Unix Network Programing》W.Richard Stevens:第一卷讲BSD Socket网络编程接口和另外一种网络编程接口的,不过现在一般都用BSD Socket,所以这本书只要看大约一半多就可以了。第二卷没有设计到网络的东西,主要讲进程间通讯和Posix线程。所以看了《APUE》以后,就可以 看它了,基本上系统的东西就由《APUE》和《UNP》vol2概括了。看过《UNP》以后,您就会知道系统编程的绝大部分编程技巧,即使卷一是讲网络编 程的。国内是清华翻译得《Unix网络编程》,翻译者得功底也比较高,翻译地比较好。所以建议还是看中文版。

  《TCP/IP祥解》一共三卷,卷一讲协议,卷二讲实现,卷三讲编程应用。我没有怎么看过。,但是据说也很经典的,因为我没有时间看卷二,所以不便评价。

  《用TCP/IP进行网际互连》Douglus.E.Comer 一共三卷,卷一讲原理,卷二讲实现,卷三讲高级协议。感觉上这一套要比Stevens的那一套要好,就连Stevens也不得不承认它的第一卷非常经典。 事实上,第一卷即使你没有一点网络的知识,看完以后也会对网络的来龙去脉了如指掌。第一卷中还有很多习题也设计得经典和实用,因为作者本身就是一位教师, 并且卷一是国外研究生的教材。习题并没有答案,留给读者思考,因为问题得答案可以让你成为一个中级的Hacker,这些问题的答案可以象Douglus索 取,不过只有他只给教师卷二我没有怎么看,卷三可以作为参考手册,其中地例子也很经典。如果您看过Qterm的源代码,就会知道Qterm的telnet 实现部分大多数就是从这本书的源代码过来的。对于网络原理的书,我推荐它,而不是Stevens的《TCP/IP祥解》。

  《Operating System - Design and Implement》这个是讲操作系统的书,用Minix做的例子。作者母语不是英文,所以英文看起来比较晦涩。国内翻译的是《操作系统 设计与实现》,我没看过中文版,因为翻译者是尤晋元,他翻译的《APUE》已经让我失望头顶了。读了这本书,对操作系统的底层怎么工作的就会
有一个清晰的认识。

  《Linux Device Driver》2e ,为数不多的关于Linux设备驱动程序的好书。不过内容有些杂乱,如果您没有一些写驱动的经验,初次看会有些摸不着南北。国内翻译的是《Linux设备 驱动程序》第二版,第一版,第二版的译者我都有很深的接触,不过总体上来说,虽然第二版翻译的有些不尽人意,但是相比第一版来说已经超出了一大截。要读这 一本书,至少应该先找一些《计算机原理》《计算机体系结构》的书来马马虎虎读读,至少应该对硬件和计算机的工作过程有一些了解。

GNU Profiler(GProf): 度量程序性能

<<程序设计实践>>:

“使用轮廓程序。除了可靠的计时方法外,在性能分析中最重要的工具就是一种能产生轮廓文件的系统。轮廓文件是对程序在哪些地方消耗了时间的一种度量。在 有些轮廓文件中列出了执行中调用的各个函数、各函数被调用的次数以及它们消耗的时间在整个执行中的百分比。另一些轮廓文件计算每个语句执行的次数。执行非 常频繁的语句通常对总运行时间的贡献比较大,根本没执行的语句所指明的可能是些无用代码,或者是没有合理测试到的代码。轮廓文件是一种发现程序中执行热点的有效手段,所谓热点就是那些消耗了大部分计算时间的函数或者代码段。当然,对轮廓文件的解释也应该慎重。由于编译程序本身的复杂性、缓冲存储器和主存的复杂影响,还有做程序的轮廓文件对其本身执行所造成的影响等,轮廓文件的统计信息只能看作是近似的.轮廓文件常常可以通过编译系统的一个标志或选择项打开,然后运行程序,最后用一个分析工具显示结果。在U n i x上,这个标志一般是- p,对应的工具是p r o f“

---------------------------------------------------------

来源:

blog.csdn.net/lengxingfei/archive/2006/01/20/584889.aspx

在优化程序的时候,要记住:在值得优化的地方优化!没有必要花上几个小时来优化一段实际上只运行0.04秒的程序。

GProf 使用了一种异常简单但是非常有效的方法来优化C/C++ 程序,而且能很容易的识别出值得优化的代码。一个简单的案例分析将会显示,GProf如何通过识别并优化两个关键的数据结构,将实际应用中的程序从3分钟的运行时优化到5秒的。

这个程序最早可以追溯到1982年关于编译器构建的特别讨论大会(the SIGPLAN Symposium on Compiler Construction)。现在这个程序成了各种UNIX 平台上的一个标准工具。

_________________ _________________ _________________


 

Profiling in a nutshell

程序概要分析的概念非常简单:通过记录各个函数的调用和结束时间,我们可以计算出程序的最大运行时的程序段。 这种方法听起来似乎要花费很多气力——幸运的是,我们其实离真理并不远!我们只需要在用 gcc 编译时加上一个额外的参数('-pg'),运行这个(编译好的)程序(来搜集程序概要分析的有关数据),然后运行'gprof'以更方便的分析这些结果。

 

案例分析: Pathalizer

我使用了一个现实中使用的程序来作为例子,是pathalizer的一部分: 即 event2dot,一个将路径“事件”描述文件转化为图形化“dot”文件的工具(executable which translates a pathalizer 'events' file to a graphviz 'dot' file)。

 

简单的说,它从一个文件里面读取各种事件,然后将它们分别保存为图像(以页为节点,且将页与页之间的转变作为边),然后将这些图像整合为一张大的图形,并保存为图形化的'dot'格式文件。  

给程序计时

先让我们给我们未经优化的程序计一下时,看看它们的运行要多少时间。在我的计算机上使用event2dot并用源码里的例子作为输入(大概55000的数据),大致要三分多钟:

 

 

real    3m36.316s
user    0m55.590s
sys     0m1.070s

 

程序分析

要使用gprof 作概要分析,在编译的时候要加上'-pg' 选项,我们就是如下重新编译源码如下:

g++ -pg dotgen.cpp readfile.cpp main.cpp graph.cpp config.cpp -o event2dot

现在我们可以再次运行event2dot,并使用我们前面使用的测试数据。这次我们运行的时候,event2dot运行的分析数据会被搜集并保存在'gmon.out'文件中,我们可以通过运行'gprof event2dot | less'来查看结果。

gprof 会显示出如下的函数比较重要:

 % cumulative  self              self     total
 time seconds  seconds  calls s/call s/call name
43.32   46.03  46.03 339952989  0.00  0.00 CompareNodes(Node *,Node *)
25.06   72.66  26.63    55000   0.00  0.00 getNode(char *,NodeListNode *&)
16.80   90.51  17.85 339433374  0.00  0.00 CompareEdges(Edge *,AnnotatedEdge *)
12.70  104.01  13.50    51987   0.00  0.00 addAnnotatedEdge(AnnotatedGraph *,Edge *)
 1.98  106.11   2.10    51987   0.00  0.00 addEdge(Graph *,Node *,Node *)
 0.07  106.18   0.07        1   0.07  0.07 FindTreshold(AnnotatedEdge *,int)
 0.06  106.24   0.06        1   0.06 28.79 getGraphFromFile(char *,NodeListNode *&,Config *)
 0.02  106.26   0.02        1   0.02 77.40 summarize(GraphListNode *,Config *)
 0.00  106.26   0.00    55000   0.00  0.00 FixName(char *)

可以看出,第一个函数比较重要: 程序里面绝大部分的运行时都被它给占据了。

 

优化

上面结果可以看出,这个程序大部分的时间都花在了CompareNodes函数上,用 grep 查看一下则发现CompareNodes 只是被 CompareEdges调用了一次而已, 而CompareEdges则只被 addAnnotatedEdge调用——它们都出现在了上面的清单中。这儿就是我们应该做点优化的地方了吧!

 

我们注意到addAnnotatedEdge遍历了一个链表。虽然链表是易于实现,但是却实在不是最好的数据类型。我们决定将链表 g->edges 用二叉树来代替: 这将会使得查找更快。  

结果

现在我们看一下优化后的运行结果:

real    2m19.314s
user    0m36.370s
sys     0m0.940s

 

第二遍

再次运行 gprof 来分析:

%   cumulative self           self    total
 time   seconds seconds calls  s/call  s/call name
87.01     25.25  25.25  55000    0.00    0.00 getNode(char *,NodeListNode *&)
10.65     28.34   3.09  51987    0.00    0.00 addEdge(Graph *,Node *,Node *)

看起来以前占用大量运行时的函数现在已经不再是占用运行时的大头了!我们试一下再优化一下呢:用节点哈希表来取代节点树。

这次简直是个巨大的进步:

real    0m3.269s
user    0m0.830s
sys     0m0.090s

            

--------------------------------------------------------

另外,还可以参考:

使用 GNU profiler 来提高代码运行速度

寻找应用程序中占用时间最长的部分

www.ibm.com/developerworks/cn/linux/l-gnuprof.html                                     

GObject, Glib, GDK, GTK+...

原本只是打算学习怎么使用GTK+进行图形界面的开发,不过在看了tigersoldier写的控件之后,对GTK+的内部机制产生了强烈的好奇心,于是下载了源码来看。

结果,越看越迷糊,涉及到的内容好多:

GObject:

“GObject provides the object system used for Pango and GTK+.”

Glib:

"GLib provides the core application building blocks for libraries and applications written in C. It provides the core object system used in GNOME, the main loop implementation, and a large set of utility functions for strings and common data structures."

GDK:

"An intermediate layer which isolates GTK+ from the details of the windowing system."

GTK+

"GTK+ is the primary library used to construct user interfaces in GNOME applications. It provides user interface controls and signal callbacks to control user interfaces."

 

目标是彻底理解下面这段最简单的GTK+代码的工作原理及实现:

 

#include<gtk/gtk.h>

static gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
    gtk_main_quit();
}

int main(int argc, char *argv[])
{
        GtkWidget *window;

        gtk_init(&argc, &argv);

        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

        g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), NULL);

        gtk_widget_show(window);

        gtk_main();

        return 0;
}

 

 

加油,加油...

 

GLib的一些规范

来源:

imtx.cn/archives/167.html

 

在一些面向对象的程序语言中,有一些内置方法,是用来取得类的所属关系或者类型。比如Python中,用type来取得实例的类型。

GLib中规定了一些规范来实现这个。 这是在学用GObject定义自己的类型前需要注意的。

当用户在头文件中创建新类型时,有一些规范用户需要注意:

  • 使用object_method的形式来定义函数名称:例如在一个bar类中定义一个名为foo的函数,则用bar_foo。
  • 使用前缀来避免与其他工程的命名空间冲突。如果你的库(或应用程序)名为Marman,那么所有的函数名称前缀为maman_。举例:maman_object_method。
  • 创建一个宏命为PREFIX_OBJECT_TYPE用来返回GType关联的对象类型。比如,Bar这个类在一个以maman前缀的库中,则使用 MANMAN_BAR_TYPE。另有一个不成文的规定是,定义一个使用全局静态变或一个名为prefix_object_get_type的函数来实现 这个宏。我们将在后面的章节中讨论这个函数。
  • 创建一个宏命名为PREFIX_OBJECT(obj)来返回一个指向 PrefixObject类型的指针。这个宏用于必要时安全地强制转换一个静态类型。运行环境检查时,同样也是安全地执行动态类型。在处理过程中禁用动态 类型检查是可行的。例如,我们可以创建MAMAN_BAR(obj)来保持先前的例子。
  • 如果类型是类化的,那么创建一个命令为 PREFIX_OBJECT_CLASS(klass)的宏。这个宏与前面那个是非常相似的:它以类结构的动态类型检查来进行静态转换,并返回一个指向 PrefixObjectClass这个类型的类结构的指针。同样,例子为:MAMAN_BAR_CLASS。
  • 创建一个宏命名为PREFIX_IS_BAR (obj):这个宏用于判断输入的对象实例是否是BAR类型的。
  • 如果类型是类化的,创建一个名为PREFIX_IS_OBJECT_CLASS (klass)的宏,与上面的类似,返回输入的类型指针是否是OBJECT类型。
  • 如果类型是类化的,创建一个名为PREFIX_OBJECT_GET_CLASS,返回一个实例所属的类的类型指针。这个宏因为安全的原因,被静态和动态类型所使用,就像上面的转换宏一样。

至于这些宏的实现是非常直观的:一些数量的简单使用的宏由gtype.h提供。针对上面我们兴趣的例子,我们写了下面的代码来声明这些宏:

 

#define MAMAN_BAR_TYPE                  (maman_bar_get_type ())

#define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_BAR_TYPE, MamanBar))

#define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_BAR_TYPE, MamanBarClass))

#define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_BAR_TYPE))

#define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_BAR_TYPE))

#define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_BAR_TYPE, MamanBarClass))

 
GType maman_bar_get_type (void)

{

static GType type = 0;

if (type == 0) {

static const GTypeInfo info = {

/* You fill this structure. */

};

type = g_type_register_static (G_TYPE_OBJECT,

"MamanBarType",

&info, 0);

}

return type;

}

 

例子(GtkWindow):

 

#define GTK_TYPE_WINDOW            (gtk_window_get_type ())
#define GTK_WINDOW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WINDOW, GtkWindow))
#define GTK_WINDOW_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WINDOW, GtkWindowClass))
#define GTK_IS_WINDOW(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WINDOW))
#define GTK_IS_WINDOW_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WINDOW))
#define GTK_WINDOW_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WINDOW, GtkWindowClass))

 

 

GTK系统添加建立一种新的“类型”的过程

来源:

blog.csai.cn/user1/265/archives/2005/786.html

 

GTK对象系统运行时,为支持对象的动态创建和销毁,系统中必定会拥有所有对象“类型”之间的 关联表,也即所有_GtkTypeNode实体组织而成的“类继承树”,每个_GtkTypeNode代表一种“类型”,它包含了指向 _GtkTypeInfo,以及从_GtkObjectClass派生出的结构的数据信息,所以,我们可以轻松通过GtkType来遍历系统中所有的类 型。

为系统添加建立一种新的“类型”的过程很简单,它一般由gtk_xxx_get_type()触发,例如 gtk_window_get_type()函数。注意,一种新“类型”被加入时,它会创建一个_GtkTypeNode的数据结构,并添入到系统的“类 继承树”中,具体的过程参阅下面的源代码:

Realizing, Mapping, and Showing

From: developer.gnome.org/doc/GGAD/z57.html

 

Fully understanding GTK+ requires some minimal understanding of the X Window System. This book assumes you have a user-level understanding---you know what an X server is, that X is network transparent, what a window manager does, and so on. A few more details are needed to write programs, however.

One detail is particularly important: the X Window System maintains a tree of windows. "Window" in this sense refers to an X window, not a GtkWindow---GtkWindow is a GTK+-specific concept, a widget that corresponds to an application's toplevel X window. An X window is not the user-visible concept "window" represented by GtkWindow; rather, it's an abstraction used by the X server to partition the screen. The "background" displayed by your X server is the root window; the root window has no parent. Application windows are typically near-children of the root window; most window managers create a child of the root window to hold the window's titlebar and other decorations, and place the application window inside. Window managers have total control over application windows---they can reposition them, reparent them, and iconify them at will. Application windows can in turn contain subwindows, which are controlled by the application. Note that GTK+ uses the GDK library, rather than using X directly; in GDK, there is a thin X window wrapper called GdkWindow. Don't confuse GdkWindow and GtkWindow.

An X window, or a GdkWindow, gives the X server hints about the structure of the graphics being displayed. Since X is network transparent, this helps reduce network traffic. The X server knows how to show windows on the screen; hide them; move them around (keeping children in position relative to their parents); capture events such as mouse movements on a per-window basis; and so on. A GdkWindow is also the fundamental unit for drawing graphics---you can't draw to "the screen" as a whole, you must draw on a GdkWindow.

Most GTK+ widgets have a corresponding GdkWindow. There are exceptions, such as GtkLabel; these are referred to as "no window widgets," and are relatively lightweight. Widgets with no associated GdkWindow draw into their parent's GdkWindow. Some operations, such as capturing events, require a GdkWindow; thus they are impossible on no-window widgets.

Widgets pass through a number of states related to their GdkWindow:

  • A widget is said to be realized if its corresponding GdkWindow has been created. Widgets are realized via gtk_widget_realize(), and unrealized via gtk_widget_unrealize(). Since an X window must have a parent, if a widget is realized its parent must also be.

  • A widget is mapped if gdk_window_show() has been called on its GdkWindow. This means the server has been asked to display the window on the screen; obviously the GdkWindow must exist, implying that the widget is realized.

  • A widget is visible if it will automatically be mapped when its parent is mapped. This means that gtk_widget_show() has been called on the widget. A widget can be rendered invisible by calling gtk_widget_hide(); this will either unschedule the pending map, or unmap the widget (hide its GdkWindow). Since toplevel widgets have no parent, they are mapped as soon as they are shown.

In typical user code, you only need to call gtk_widget_show(); this implies realizing and mapping the widget as soon as its parent is realized and mapped. It's important to understand that gtk_widget_show() has no immediate effect, it merely schedules the widget to be shown. This means you don't have to worry about showing widgets in any particular order; it also means that you can't immediately access the GdkWindow of a widget. Sometimes you need to access the GdkWindow; in those cases you'll want to manually call gtk_widget_realize() to create it. gtk_widget_realize() will also realize a widget's parents, if appropriate. It's uncommon to need gtk_widget_realize(); if you find that you do, perhaps you are approaching the problem incorrectly.

Destroying a widget automatically reverses the entire sequence of events, recursively unrealizing the widget's children and the widget itself.

Figure 23 summarizes the functions discussed in this section.

#include <gtk/gtkwidget.h>

void gtk_widget_realize(GtkWidget* widget);

void gtk_widget_unrealize(GtkWidget* widget);

void gtk_widget_map(GtkWidget* widget);

void gtk_widget_unmap(GtkWidget* widget);

void gtk_widget_show(GtkWidget* widget);

void gtk_widget_hide(GtkWidget* widget);

Figure 23. Showing/Realizing Widgets

Figure 24 summarizes macros for querying the states discussed in this section.

#include <gtk/gtkwidget.h>

GTK_WIDGET_NO_WINDOW(widget);

GTK_WIDGET_REALIZED(widget);

GTK_WIDGET_MAPPED(widget);

GTK_WIDGET_VISIBLE(widget);

Figure 24. Widget Predicates

在屏幕上显示构件

在屏幕上显示需要几个相关步骤。在调用 WIDGETNAME_new() 创建构件之后,如下几个函数需要用到:

你可能注意到后面的两个函数十分相似,都是负责在屏幕上绘制构件。实际上许多构件并不真正关心它们之间的不同。构件类里的默认 draw() 函数只是简单的为重绘区域产生一个暴露事件。然而,一些构件通过区分这两个函数可以减少操作。例如,如果一个构件有多个 X 窗口,因为暴露事件标识了暴露的窗口,它可以只重绘受影响的窗口,调用 draw() 是不可能这样的。

容器构件,即使它们自身并不关心这个差别,也不能简单的使用默认 draw() 函数,因为它的子构件可能需要注意这个差别。然而,在两个函数里重复绘制代码是一种浪费的。按惯例,构件有一个名为 WIDGETNAME_paint() 的函数做实际的绘制构件的工作,draw()expose() 函数再调用它。

APUE 线程私有数据与errno的实现

线程私有数据

每个线程可以独立地访问数据副本,而不需要担心与其他线程的同步访问问题。

它提供了让基于进程的接口适应多线程环境的机制,一个很明显的实例就是errno。为了让线程也能够使用那些原本基于进程的系统调用和库例程,errno被重新定义为线程私有数据。这样,一个线程设置errno的操作并不会影响进程中其他线程的errno值。

 

#include<pthread.h>

int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void *));

“键”可以被进程中的所有线程使用,而每个线程把这个键与不同的线程私有数据地址进行关联,这就是其基本原理。

 

errno的定义

 

在<errno.h>头文件中:

/* Declare the `errno' variable, unless it's defined as a macro by
   bits/errno.h.  This is the case in GNU, where it is a per-thread
   variable.  This redeclaration using the macro still works, but it
   will be a function declaration without a prototype and may trigger
   a -Wstrict-prototypes warning.  */

#ifndef errno
extern int errno;
#endif

在<bits/errno.h>头文件中:

# ifndef __ASSEMBLER__
/* Function to get address of global `errno' variable.  */
extern int *__errno_location (void) __THROW __attribute__ ((__const__));

#  if !defined _LIBC || defined _LIBC_REENTRANT
/* When using threads, errno is a per-thread value.  */
#   define errno (*__errno_location ())
#  endif
# endif /* !__ASSEMBLER__ */


errno实际上,并不是我们通常认为的是个整型数值,而是通过整型指针来获取值的。这个整型就是线程安全的。

另外,宏之所以这样实现,是因为标准库规定了必须能够通过&errno方式取得保存错误代码的变量的地址,因此__errno_location()函数的返回值是指针,并把宏定义为解引用函数返回的地址*__errno_location()。如果__errno_location直接返回int类型,此时就无法取得保存错误代码的变量的地址。

 

errno的可能实现

 

#include<stdlib.h>
#include<pthread.h>

static pthread_key_t key;
static pthread_once_t init_done = PTHREAD_ONCE_INIT;

static void
thread_init(void)
{
        pthread_key_create(&key, free);
}

int *
__errno_location_simply_fake(void)
{
        int *errp;

        /* 保证多线程环境里 key 只被创建一次 */
        pthread_once(&init_done, thread_init);

        errp = (int *)pthread_getspecific(key);
        if(errp == NULL) {
                errp = malloc(sizeof(int));
                if(errp != NULL)
                        pthread_setspecific(key, errp);
        }

        return errp;
}

 

参考:

1. 《APUE》第12.6节 线程私有数据

2. blog.csdn.net/romandion/archive/2008/01/11/2036975.aspx

3. bbs.chinaunix.net/viewthread.php

 

linux errno code

 

来源: blog.csdn.net/wei801004/archive/2007/03/05/1521100.aspx

   124 EMEDIUMTYPE   Wrong medium type
   123 ENOMEDIUM     No medium found
   122 EDQUOT        Disk quota exceeded
   121 EREMOTEIO     Remote I/O error
   120 EISNAM        Is a named type file
   119 ENAVAIL       No XENIX semaphores available
   118 ENOTNAM       Not a XENIX named type file
   117 EUCLEAN       Structure needs cleaning
   116 ESTALE        Stale NFS file handle
   115 EINPROGRESS  +Operation now in progress
   114 EALREADY      Operation already in progress
   113 EHOSTUNREACH  No route to host
   112 EHOSTDOWN     Host is down
   111 ECONNREFUSED  Connection refused
   110 ETIMEDOUT    +Connection timed out
   109 ETOOMANYREFS  Too many references: cannot splice
   108 ESHUTDOWN     Cannot send after transport endpoint shutdown
   107 ENOTCONN      Transport endpoint is not connected
   106 EISCONN       Transport endpoint is already connected
   105 ENOBUFS       No buffer space available
   104 ECONNRESET    Connection reset by peer
   103 ECONNABORTED  Software caused connection abort
   102 ENETRESET     Network dropped connection on reset
   101 ENETUNREACH   Network is unreachable
   100 ENETDOWN      Network is down
    99 EADDRNOTAVAIL Cannot assign requested address
    98 EADDRINUSE    Address already in use
    97 EAFNOSUPPORT  Address family not supported by protocol
    96 EPFNOSUPPORT  Protocol family not supported
    95 EOPNOTSUPP    Operation not supported
    94 ESOCKTNOSUPPORT Socket type not supported
    93 EPROTONOSUPPORT Protocol not supported
    92 ENOPROTOOPT   Protocol not available
    91 EPROTOTYPE    Protocol wrong type for socket
    90 EMSGSIZE     +Message too long
    89 EDESTADDRREQ  Destination address required
    88 ENOTSOCK      Socket operation on non-socket
    87 EUSERS        Too many users
    86 ESTRPIPE      Streams pipe error
    85 ERESTART      Interrupted system call should be restarted
    84 EILSEQ        Invalid or incomplete multibyte or wide character
    83 ELIBEXEC      Cannot exec a shared library directly
    82 ELIBMAX       Attempting to link in too many shared libraries
    81 ELIBSCN       .lib section in a.out corrupted
    80 ELIBBAD       Accessing a corrupted shared library
    79 ELIBACC       Can not access a needed shared library
    78 EREMCHG       Remote address changed
    77 EBADFD        File descriptor in bad state
    76 ENOTUNIQ      Name not unique on network
    75 EOVERFLOW     Value too large for defined data type
    74 EBADMSG      +Bad message
    73 EDOTDOT       RFS specific error
    72 EMULTIHOP     Multihop attempted
    71 EPROTO        Protocol error
    70 ECOMM         Communication error on send
    69 ESRMNT        Srmount error
    68 EADV          Advertise error
    67 ENOLINK       Link has been severed
    66 EREMOTE       Object is remote
    65 ENOPKG        Package not installed
    64 ENONET        Machine is not on the network
    63 ENOSR         Out of streams resources
    62 ETIME         Timer expired
    61 ENODATA       No data available
    60 ENOSTR        Device not a stream
    59 EBFONT        Bad font file format
    57 EBADSLT       Invalid slot
    56 EBADRQC       Invalid request code
    55 ENOANO        No anode
    54 EXFULL        Exchange full
    53 EBADR         Invalid request descriptor
    52 EBADE         Invalid exchange
    51 EL2HLT        Level 2 halted
    50 ENOCSI        No CSI structure available
    49 EUNATCH       Protocol driver not attached
    48 ELNRNG        Link number out of range
    47 EL3RST        Level 3 reset
    46 EL3HLT        Level 3 halted
    45 EL2NSYNC      Level 2 not synchronized
    44 ECHRNG        Channel number out of range
    43 EIDRM         Identifier removed
    42 ENOMSG        No message of desired type
    40 ELOOP         Too many levels of symbolic links
    39 ENOTEMPTY    +Directory not empty
    38 ENOSYS       +Function not implemented
    37 ENOLCK       +No locks available
    36 ENAMETOOLONG +File name too long
    35 EDEADLK      +Resource deadlock avoided
    34 ERANGE       +Numerical result out of range
    33 EDOM         +Numerical argument out of domain
    32 EPIPE        +Broken pipe
    31 EMLINK       +Too many links
    30 EROFS        +Read-only file system
    29 ESPIPE       +Illegal seek
    28 ENOSPC       +No space left on device
    27 EFBIG        +File too large
    26 ETXTBSY       Text file busy
    25 ENOTTY       +Inappropriate ioctl for device
    24 EMFILE       +Too many open files
    23 ENFILE       +Too many open files in system
    22 EINVAL       +Invalid argument
    21 EISDIR       +Is a directory
    20 ENOTDIR      +Not a directory
    19 ENODEV       +No such device
    18 EXDEV        +Invalid cross-device link
    17 EEXIST       +File exists
    16 EBUSY        +Device or resource busy
    15 ENOTBLK       Block device required
    14 EFAULT       +Bad address
    13 EACCES       +Permission denied
    12 ENOMEM       +Cannot allocate memory
    11 EAGAIN       +Resource temporarily unavailable
    10 ECHILD       +No child processes
     9 EBADF        +Bad file descriptor
     8 ENOEXEC      +Exec format error
     7 E2BIG        +Argument list too long
     6 ENXIO        +No such device or address
     5 EIO          +Input/output error
     4 EINTR        +Interrupted system call
     3 ESRCH        +No such process
     2 ENOENT       +No such file or directory
     1 EPERM        +Operation not permitted
#    0 --            Success

Ubuntu: ThinkPad SL400的无线上网问题

话说,前几天跟死党们一起去图书馆准备享受无线上网的乐趣(之前大家说好,拿着四台本,然后一起去图书馆玩QQ游戏,呵呵)。

结果,唯独我的笔记本连无线都开不了,汗...记得刚买笔记本的时候成功使用过无线上网,难道那时还是Vista?

无奈之下,还是只能求助于万能的Google:

于是,找到了 madwifi 这个东东,介绍见: madwifi.org

"This software contains a Linux kernel driver for Atheros-based Wireless LAN devices.  The driver supports station, AP, ad-hoc, and monitor modes
of operation.  The Atheros driver depends on a device-independent implementation of the 802.11 protocols that originated in the BSD
community (NetBSD in particular)."

运行lspci找到如下结果:

Ethernet controller: Atheros Communications Inc. AR242x 802.11abg Wireless PCI Express Adapter (rev 01)

安装Madwifi(具体内容参考INSTALL):

下载最新的madwifi-hal-0.10.5.6

sudo make clean

sudo make

sudo make install

sudo modprobe ath_pci

sudo gedit /etc/modules文件,在最后加上一行: ath_pci


 

僵死进程

APUE 第8章:

如果子进程在父进程之前终止,那么父进程又如何能在做相应检查时得到子进程的终止状态呢?

对此问题的回答是:内核为每个终止子进程保存了一定量的信息,所以当父进程调用wait或者waitpid时,可以得到这些信息,这些信息至少包括进程ID,终止状态,以及该进程使用的CPU时间总量。内核可以释放终止进程所使用的所有存储区,关闭其所有打开的流等。

一个已经终止,但是其父进程尚未对其进行善后处理(获取终止子进程的有关信息等)的进程被称为僵死进程(zombie)

 

想到的一个问题就是:终止子进程处于僵死进程直到什么时候为止?

于是google之:

来源: blogs.sun.com/haifeng/entry/unix_%E5%83%B5%E6%AD%BB_zombie_%E8%BF%9B%E7%A8%8B1

进程在它的生命周期有几种状态:睡眠,可运行,停止,正在运行和僵死状态。 所谓僵死进程,指的是一个进程已经退出,它的内存和相关的资源已经被内核释放掉,但是在进程表中这个进程项(entry)还保留着,以便它的父进程得到它 的退出状态。 一个进程退出时,它的父进程会收到一个SIGCHLD信号。一般情况下,这个信号的句柄通常执行wait系统调用,这样处于僵死状态的进程会被删除。 如果父进程没有这么做,结果是什么呢?毫无疑问,进程会处于僵死状态。 实际上,僵死进程不会对系统有太大的伤害,最多就是它的进程号(PID)和进程表中的进程项系统不能使用。(感觉这里说的更加清楚,难道是中文版翻译的不行呵呵)

去掉僵尸进程

在Solaris中,可以用ptree命令列出所有进程,查找进程名称为“defunct”的进程。如果发现了,那么系统存在僵死进程。 注意用kill命令不能杀死这种进程。原因是它已经退出了,什么也没有了,自然无法收到任何信号。

删除僵尸进程的根本方法是让它的父进程调用wait来处理SIGCHLD信号。有两种方式可以做到这一点。一种方法是改变它的父进程。可以用kill命令 杀死它的父进程,这样init变成它的新的父进程,而init会定时地执行wait系统调用。另一种方式是使用调试器,在父进程中执行wait系统调用。 如果知道了父进程的程序名称和它的进程号,运行下面命令:

   %gdb `parent application name` `parent pid`
   (gdb) set unwindonsignal on
   (gdb) call wait(pid of zombie process)

gdb会在父进程中调用wait,从而达到我们的目的。注意,unwindonsignal要被set为on, 它告诉gdb把堆栈恢复到调用wait之前的状态。要不然父进程会crash。 在程序中避免僵死进程 除了显式调用wait或waitpid外,也可以使用下面的代码来避免僵死进程(这儿假设父进程对子进程的状态不感兴趣),它遵循POSIX,是可移植 的。

   struct sigaction sa;
   sa.sa_handler = SIG_IGN;
   sa.sa_flags = SA_NOCLDWAIT;
   sigemptyset (&sa.sa_mask);
   sigaction (SIGCHLD, &sa, NULL);

参考exit(2)手册页。

 

来源: www.chinaunix.net/jh/4/665906.html

一、僵屍進程的産生

当子进程比父进程先运行结束,而父进程没有回收子进程的时候,子进程将成为一个僵尸进程。如果父进程先退出,子进程被init接管,子进程退出后init会回收,就没事了。

二、僵屍進程的危害

僵尸进程是一个运行完毕的进程,所有资源都已经释放了,除了它的进程表项。因此,导致的影响如下:如果操作系统最多能管理1000个进程,那么僵尸进程的存在,将会使得操作系统管理正常进程减少。

三、如何避免僵屍進程的産生

1、父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起

2. 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后,父进程会收到该信号,可以在handler中调用wait回收

3. 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号

4. 还有一些技巧,就是fork两次(APUE有介绍),父进程fork一个子进程,然后继续工作,子进程fork一个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收估计还要自己做。