免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1359 | 回复: 0
打印 上一主题 下一主题

Linux编程库 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-08-17 02:13 |只看该作者 |倒序浏览


  • Linux编程库简介
    所谓Linux编程库就是指始终可以被多个Linux软件项目重复使用的代码集。以C语言为例,它包含了几百个可以重复使用的例程和调试程序的工具代码,其中包括函数。如果每次编写新程序都要重新写这些代码会非常不方便,使用编程库有两个主要优点:


    • 可以简化编程,实现代码重复使用,进而减小应用程序的大小;

    • 可以直接使用比较稳定的代码。

    Linux下的库文件分为共享库和静态库2大类,它们两者之间的差别仅在程序执行时所需的代码是在运行时动态加载的,还是在编译时竟态加载的。此外,通常共享库以.so(Share Objece)结尾,静态链接库通常以.a结尾(Archive)。在终端下查看库的内容,通常共享库为绿色,静态库为黑色。
    Linux库一般在/lib或/usr/lib目录下。它主要存放系统得链接库文件,没有该目录则系统无法正常运行。/lib目录存储着程序运行时使用的共享库。通过共享库,许多程序可以重复使用相同的代码,因此可以有效减小应用程序的大小。下表部分列出了一些Linux下常用到的编程库。
    常用到的Linux编程库
    库 名 称
    说 明
    libc.so
    标准的C库
    libdl.so
    可使用库的源代码而无需静态编译库
    libglib.so
    Glib库
    libm.so
    标准数学库
    libGL.so
    OpenGL的接口
    libcom_err.so
    常用的出错例程集合
    libdb.so
    创建和操作数据库
    libgthread.so
    Glib线程支持
    libgtk.so
    GIMP下的X库
    libz.so
    压缩例程库
    libvga.so
    Linux下的VGA和SVGA图形库
    libresolve.so
    提供使用因特网域名服务器接口
    libpthread.so
    Linux多线程库
    libdm.so
    GNU数据库管理器

  • Linux系统调用
    从字面意思上理解,系统调用说的是操作系统提供给用户程序调用的一组“特殊”接口。Linux中用于创建进程的fork()函数本身就是一个系统调用,使用系统主要目的是使得用户可以使用操作系统提供的有关设备管理、输入/输出系统、文件系统和进程控制、通信以及存储管理等方面的功能,而不必了解系统程序的内部结构和有关硬件细节,从而起到减轻用户负担和保护系统以及提高资源利用率的作用。
    Linux的运行空间划分为用户空间和内核空间,它们各自运行在不同的级别中,所以用户进程通常情况下不允许访问内核,也无法使用内核函数,它们只能在用户空间操作用户数据,调用用户空间函数。这样做的目的是为了对系统作必要的“保护”措施,但是使用系统调用可以最大程度地解决这一问题。其具体的措施是进程先用适当的值填充寄存器,然后调用一个特殊的指令,这个指令会跳到一个事先定义的内核中的一个位置(当然,这个位置是用户进程可读但是不可写的)。硬件知道一旦用户进程跳到这个位置,则认为该用户就不是在限制模式下运行的用户,而作为操作系统的内核。当然,用户访问内核的路径是事先规定好的,只能从规定位置进入内核,而不允许任意跳入内核。
    Linux系统有200多个系统调用,这些调用按照功能大致可以分为下面几类:


    • 进程控制

    • 文件系统控制

    • 内存管理

    • 网络管理

    • Socket控制

    • 用户管理

    • 进程间通信

    类似于在Windows下进行win32编程,windows会提供API(Application Programming
    Interface)接口函数作为为windows操作系统提供给程序员的系统调用接口。同样的,Linux作为一个操作系统也有它自己的系统调用,用户可以根据特定的方法来添加需要的系统调用。Linux的API接口遵循POSIX标准,这套标准定义了一系列API。在Linux中,这些API主要是通过C库(libc)实现的。下面通过举例来说明在Linux下添加新的系统调用的几个步骤。
    (1)修改kernel/sys.c,增加服务例程代码。首先编写添加到内核中的源程序。即要添加的服务,所以函数的名称应该是新的系统调用名称前面加上sys_标志。例如新加的系统调用为mysyscall(int number),那么就应该在系统的/usr/linux/kernel/sys.c文件中添加相应的源代码,如下所示。
    asmlinkage int sys_mysyscall (int number)
    {
    printk(“This is a example of systemcall\n”);
    return number;
    }
    为了说明问题,仅仅是一个返回一个值的简单例子。
    ………………………………………………………………………………………………………
    注意:系统调用函数通常在成功时返回0值,不成功时返回非零值
    ………………………………………………………………………………………………………..
    (2)添加新的系统调用后,为了从已有的内核程序中增加到新的函数的连接,需要编辑以下2个文件。
    1、/usr/src/linux/include/asm-i386/unistd.h
    2、/usr/src/linux/arch/i386/kernel/syscall_table.S
    第一个文件中定义了每个系统调用的中断号,可以打开文件/usr/src/linux/include/ asm-i386/unistd.h来查看,该文件中包含了系统调用清单,用来给每个系统调用分配一个唯一的号码,部分内容如下。
    ………..
    #define __NR_add_key 286
    #define __NR_request_key 287
    #define __NR_keyctl 288
    #define __NR_ioprio_set 289
    #define __NR_ioprio_get 290
    #define __NR_inotify_init 291
    #define __NR_inotify_add_watch 292
    #define __NR_inotify_rm_watch 293
    #define __NR_syscalls 294
    …………………………..
    文件的每一行各格式如下。
    #define __NR_systemcallname N
    systemcallname为系统调用名,而N则是该系统调用对应的中断号,每个系统调用都有唯一的中断号。应该将新的系统调用名称加到清单的最后,并给它分配号码序列中下一个可用的系统调用号。在该文件中的最后一句:#define __NR_stemcall 294
    NR_stemcall表示系统调用的个数,294表示有294个系统调用,从标号0开始,所以最后一个系统调用号是293,那么如果新添加一个系统调用其中断号就是294。
    例如可以在该文件中这样定义一个系统调用:
    #define __NR_mysyscall 294
    如果还需要添加另外的系统调用,可以以此类推将中断号以此递增。此外需要注意的是,重新添加系统调用之后,应该在/usr/src/linux/include/asm-i386/unistd.h文件中的#define __NR_stemcall语句重新指定新的编号N,例如上面添加一个新的系统调用之后,该语句应该为:
    #define __NR_stemcall 295
    第2个要编辑的文件是:/usr/src/linux/arch/i386/kernel/syscall_table.S。该文件中定义了系统调用列表。在该文件中有以下类似的内容。
    .data
    ENTRY(sys_call_table)
    .long sys_restart_syscall /*0 – old “setup()” system call, used for restarting*/
    .long sys_exit
    .long sys_fork
    .long sys_read
    .long sys_write
    .long sys_open
    .long sys_close
    .long sys_waitpid
    .long sys_creat
    .long sys_link
    .long sys_unlink /* 10 */
    ……………………
    在该文件中添加新的系统调用
    .long sys_mysyscall
    (3)重新编译内核。添加好系统调用之后,需要重新编译内核,并且用新的内核来启动,此时,系统调用就添加好了。
    (4)测试新的系统调用,编辑程序test_call.c如下。
    #include
    #include
    #include
    _syscall1(int, mysyscall, int, num); /*系统调用宏定义*/
    int main (void)
    {
    int n;
    n = mysyscall(10); /*执行系统调用*/
    print(“n=%d\n”,n);
    return 0;
    }
    编译并执行该程序。
    # gcc –o test_call -I/usr/src/linux/include test_call.c
    # ./test_call
    n=0
    输出值正确,说明系统调用成功。
    3 Linux线程库
    简单的讲,进程是资源管理的最小单位,线程是程序执行的最小单位。一个进程至少需要一个线程作为它的指令执行体,进程管理着资源(比如CPU、内存、文件等),而将线程分配到某个CPU上执行。一个进程当然可以拥有多个线程。
    Linux是一个多用户多任务的操作系统。多用户是指多个用户可以在同一时间使用计算机系统;多任务是指Linux可以同时执行几个任务,它可以在还未执行完一个任务时又执行另一项任务。在操作系统设计上,从进程演化出线程,最主要的目的就是更好地支持多处理器以及减小(进程/线程)上下文切换开销。
    现在多线程技术已经被许多操作系统所支持,包括Windows/Linux。现在有3种不同标准的线程库:win32,OS/2和POSIX。其中前两种只能在它们各自的平台上(win32线程仅能运行于windows平台,OS/2仅能运行于OS/2平台上)。POSIX(Portable Operating System Interface Standard,可移植操作系统接口标准)规范则是适用于各种平台,而且已经或正在所有主要的Unix/Linux系统上实现。
    Linux系统下的多线程遵循POSIX接口,称为pthread。POSIX标准由IEEE制定,并由国际标准化组织接受为国际标准。在Linux2.6内核版本之前,LinuxThreads是现有Linux平台上使用最为广泛的线程库,它由Xavier Leroy负责开发完成,并已绑定在Glib中发行。LinuxThreads是一种面向Linux的POSIX 1003.lc-pthread标准接口。它所实现的就是基于核心轻量级进程的“一对一”线程模型,一个线程实体对应一个核心轻量级进程,而线程之间的管理在核外函数库中实现。使用LinuxThreads线程库创建和管理线程常常用到下面几个函数。


    • pthread_creat() 创建新的线程

    pthread_creat()函数类似于fork()函数,完整的函数形式如下。
    int pthread_creat (pthread_t thread, const pthread_attr_t *attr, void*(*func)
    (void*), void *arg)
    第1个参数是一个pthread_t型的指针用于保存线程ID,以后对该线程的操作都要用ID来表示。每个LinuxThreads线程都同时具有线程ID和进程ID,其中进程ID就是内核所维护的进程号,而线程ID则由LinuxThreads分配和维护。
    第2个参数是一个pthread_attr_t的指针用于说明要创建的线程的属性,使用NULL表示要使用缺省的属性。
    第3个参数指明了线程运行函数的起始地址,是一个只有一个(void *)参数的函数。
    第4个参数说明了运行函数的参数,参数arg一般指向一个结构,
    函数的返回值类型为整数,当创建线程成功时,函数返回0,若不为0则说明创建线程失败。创建线程成功以后,新创建的线程运行参数3和参数4确定的函数,原来的线程则继续运行下一行代码。


    • pthread_join() 等待线程结束

    pthread_join()函数用来挂起当前线程直到由参数thread指定的线程终止为止,完整地函数形式如下。
    int pthread_join( pthread_t thread,void* *status)
    第1个参数为被等待的线程的标示符,第2个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。
    函数返回值类型为整数,成功返回0,错误返回非0值。


    • pthread_self() 获取线程ID

    函数原型
    pthread_t pthread_self(void)
    函数返回本线程ID。


    • pthread_detach() 用于让线程脱离

    pthread_detach()函数用于将处于连接状态的线程变为脱离状态,函数完整地形式如下。
    int pthread_detach (pthread_t thread)
    函数返回值类型为整数,如果成功将线程转换为脱离状态时返回0,否则返回非0值。


    • pthread_exit() 终止线程

    pthread_exit(void *status)函数用来终止线程,函数完整形式如下。
    pthread_exit(void *status)
    参数status是指向线程返回值的指针。
    下面通过一个简单的例子来介绍基于POSIX线程接口的Linux多线程编程,编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a。以下是一个简单的例子。
    /*mypthread.c*/
    #include
    #include
    #include
    void *thread_function(void *arg)
    {
    int i;
    for(i=0; i
    {
    printf(“This is a thread!\n”);
    }
    return NULL;
    }
    int main (void)
    {
    pthread_t mythread;
    if (pthread_creat (&mythread, NULL, thread_function, NULL) )
    {
    printf(“error creating thread.”);
    abort ();
    }
    printf(“This is main process!\n”);
    if ( pthread_join (mythread, NULL) )
    {
    printf(“error joining thread.”);
    abort();
    }
    exit(0);
    }
    编译并执行该程序:
    #gcc –lpthread –o mypthread mythread.c
    ./mypthread
    This is mian process!
    This is a thread!
    一个线程实际上就是一个函数,创建后,该线程立即被执行。在上面的例程中,系统创建了一个主线程,又用pthread_creat函数创建了一个新的子线程。
    事实上,在Linux2.6内核以前,Linux把进程当作其调度实体,内核并不真正支持线程(轻量线程实现)。它提供了一个clone()系统调用来创建一个调用线程的拷贝,这个拷贝与调用者共享地址空间。LinuxThreads项目就是利用这个系统调用,完全在用户级模拟了线程。LinuxThreads线程库目前存在一些不足之处,比如在信号处理、任务调度以及进程间同步原语等方面。在Linux2.6内核中,Linux内核的调度性能得到了很大改进。Linux重写了其线程库,使用NPTL(Native Posix Thread Library)来取代受争议的LinuxThreads线程库,成为glibc的首选线程库,与此同时,最新发布的glibc2.4版本正式采用NPTL作为pthread实现。


    本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/76430/showart_1132425.html
  • 您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP