linux编程入门

本人最近在复习linux编程相关的基础知识,在这里总结下,供新入门linux的同学借鉴下

先简单提一下linux吧,linux下一切皆文件,很多东西都可以用文件的一套接口来操作,比如文件,管道,设备等。linux层序一般默认打开3个文件标准输入,标准输出,标准错误输出,对应的文件描述符分别为0,1,2.。文件的基本操作有read(),write(),open(),close()ioctl(),如果你是一个linux新手的话可能有点不明所以,看下下面的代码就知道了。

1.线程创建pthread_create()   多线程代码编译的时候要加上-pthread

#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
void * ff()
{
    printf("HHHHHHHHHHHHHHHHHHHHHHHHHHHHH\n");
    pthread_exit("dfadsgagagafaggag\n");
}
void* f()
{
    sleep(5);
    pthread_t pp;
    void *rrr;
    pthread_create(&pp,NULL,ff,NULL);
    pthread_join(pp,&rrr);
    printf("in thread\n%s",(char *)rrr);
    
    pthread_exit("thank you for the CPU time\n");
    
}

int main()
{
    int ret;
    void * result;
    pthread_t th;
    ret=pthread_create(&th,NULL,f,NULL);
    sleep(1);
    //pthread_exit("I am going to exit in main");
    pthread_join(th,&result);
    printf("can you see this\n");
    printf("%s",(char *)result);
    
}

pthread_create第一个参数是线程属性,是二个pthread_attr_t的参数,线程属性请百度,这里只介绍最入门的东西,第一个参数是线程标识符的地址,第三个参数是线程入口,第四个参数是线程入口函数参数。如果在main线程中没有调用pthread_join或者pthread_exit,那么main线程退出后,其它线程即使没有执行完也要退出

pthread_join等待线程结束,参数自己看上面的代码理解下,可以画些不同的注释看看程序运行结果差别。pthread_exit如果是在main线程中运行等待所有线程结束,如果是在其他线程中执行,创建这个线程的线程再调用pthread_join可以得到它的退出状态,

2.信号量的使用

信号量是用来同步访问临界区使用的,当访问一个全局变量时,如果不加信号量或者锁的话,多线程编程中会出问题的。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include<string.h>
sem_t sem;

void exitfun()
{
    printf("exit");
}

void *f()
{    
while(1)
{
    char buf[40];
    memset(buf,0,40);
    //sem_wait(&sem);
    read(0,buf,40);
    if(strcmp(buf,"end\n")==0)
    {
        exit(0);
    }
    write(1,buf,40);
    sem_post(&sem);
    //sleep(5);
}
}    

    
int main()
{
    pthread_t pt;
    atexit(exitfun);
    pt=pthread_create(&pt,NULL,f,NULL);
    sem_init(&sem,0,1);
    while(1)
    {
        sem_wait(&sem);
        printf("in main\n");
        sleep(1);
        //sem_post(&sem);
        sleep(1);
    }
    
}

信号量有几个函数以sem_开头,wait等待信号量,post释放信号量,init初始化信号量,destroy删除信号量,init中参数第一个参数是全局信号量标识,第二个是进程私有还是进程共享,0为进程私有,第三个是信号量的初始值。看下代码可以多划些注释看看执行的结果。

3.linux文件理解

如上面信号量中的代码

read(0,buf,40);

write(1,buf,40);

文件的基本操作,不仅可以适用于文件(比如a.txt文件)对于设备也适用,linux进程默认打开三个设备标准输入,标准输出,标准错误输出,对应的设备描述符为0,1,2,标注输入一般是键盘,标注输出和标准错误输出一般是显示器。

read(0,buf,40);从键盘读取40个字符到buf数组,返回实际读取的字符长度,write向显示器写40个字符,遇到'\0'停止写。

这些方法是系统调用,还可以使用库函数scanf和printf来输入输出,scanf和prointf也是调用read和write系统调用来实现的。

在/dev下有三个文件 stdin stdou sdterr,系统默认执行了open(“/dev/stdout,0666),open(“/dev/stderr,0666),open(“/dev/stdin,0666),它们的返回值fenbie 是0,1,2.,linux中很多东西都是用这套函数来操作的。

4管道

管道分为有名管道和无名管道,

先说无名管道

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <limits.h>
#include<error.h>
#include<string.h>
void at_exit()
{    
    //printf("errno=%d\n",errno);
}

int main()
{
    int fd[2];
    int pid;
    char buf[40];
    char tembuf[40];
    
    printf("%ld     %d\n",(unsigned long)stdin,STDIN_FILENO);
    atexit(at_exit);
    if(pipe(fd)<0) 
    {    
        exit(-1);
    }
    printf("%d,%d\n",fd[0],fd[1]);

    pid=fork();
    int len;
    if(pid==0)
    {
        //printf("in child,waiting to read\n");
        close(fd[1]);

        while(1)
        {
            //len=read(STDIN_FILENO,buf,30);
            //printf("in child,read%d,letters,%s\n",len,buf);
            
            len=read(fd[0],buf,30);
            write(1,"in child",8);
            printf("%dlen=\n",len);
            write(STDOUT_FILENO,buf,len);
            printf("buf=%s\n",buf);
            write(fd[1],"hello world\n",12);
            
        }
    
    }
    if(pid>0)
    {
        //printf("in parent,waiting to read\n");
        close(fd[0]);
        while(1)
        {
            //len=read(STDIN_FILENO,buf,30);
            //printf("in parent,read%d,letters,%s\n",len,buf);
            len=read(0,tembuf,40);
            printf("%d\n",len);
            len=write(fd[1],tembuf,len);
            memset(tembuf,0,40);
            printf("in parent,write %d,%s\n",len,tembuf);
        }
    }
}

如果你的linux电脑没有打开其他设备的话你会看到fd【0】和fd【1】的值分别为3和4,fd[1]为写端,fd[0]为读端,匿名管道是半双工的,只能一端写一端读,在写端要关闭读端,在读端要关闭写端,是为了防止编程人员使用不当造成管道读写冲突,但是好像不关闭也可以,并且我试了下好像可以两端读写。我想匿名管道的设计本身并不因该提倡两端都可以读写,否则不加保护很容易出问题的。上面代码中哟一个fork系统调用,如果不清楚请百度。

有名管道

下面有两套代码,第一套可以开一个终端,第二套可以开1到多个终端,第一个代码向管道写,后面的代码读

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <limits.h>
#include<error.h>
#include<string.h>
#include <sys/stat.h>
int main()
{
    char msg[40];
    char msg1[40];
    int fd;
    int len;    
    if(mkfifo("fifo",0666)<0)
    {
        perror("mkfifo");
        printf("hhhhhhhhhhhhhhhhhh");
        exit(-1);
    }
    fd=open("fifo",0666);
    while(1)
    {    
        len=read(0,msg,40);
        printf("%s,%d\n",msg,len);
        write(fd,msg,len);
        printf("----------------------------\n");
        //len=read(fd,msg1,40);
        //printf("%s\n",msg1);
        memset(msg,0,40);
    }
}

 

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <limits.h>
#include<error.h>
#include<string.h>
#include <sys/stat.h>
int main()
{
    char msg[40];
    char msg1[40];
    int fd;
    int len;    
    fd=open("fifo",0666);
    while(1)
    {    
        len=read(fd,msg,40);
        printf("%s-------------------------\n",msg);
        sleep(3);
        memset(msg,0,40);
        
        
    }
}

创建线程后在目录下会有一个管道文件,如果不删掉,再次执行程序会直接退出,提示管道已存在。

4后续学习再,本次主要是从代码方面去理解linux这些函数。

linux内核编程 目 录 雷蒙序 简介 Linux文档工程小组“公告” 译者序 第一部分 Linux内核 前言 第1章 硬件基础与软件基础 6 1.1 硬件基础 6 1.1.1 CPU 7 1.1.2 存储器 8 1.1.3 总线 8 1.1.4 控制器和外设 8 1.1.5 地址空间 9 1.1.6 时钟 9 1.2 软件基础 9 1.2.1 计算机语言 9 1.2.2 什么是操作系统 11 1.2.3 内核数据结构 13 第2章 内存管理 15 2.1 虚拟内存抽象模型 15 2.1.1 请求调页 17 2.1.2 交换 17 2.1.3 共享虚拟内存 18 2.1.4 物理寻址模式和虚拟寻址模式 18 2.1.5 访问控制 18 2.2 高速缓存 19 2.3 Linux页表 20 2.4 页分配和回收 21 2.4.1 页分配 22 2.4.2 页回收 22 2.5 内存映射 22 2.6 请求调页 23 2.7 Linux页缓存 24 2.8 页换出和淘汰 25 2.8.1 减少缓冲区和页缓存大小 25 2.8.2 换出System V共享内存页 26 2.8.3 换出和淘汰页 27 2.9 交换缓存 27 2.10 页换入 28 第3章 进程 29 3.1 Linux进程 29 3.2 标识符 31 3.3 调度 32 3.4 文件 34 3.5 虚拟内存 35 3.6 创建进程 36 3.7 时间和定时器 37 3.8 执行程序 38 3.8.1 ELF 39 3.8.2 脚本文件 40 第4章 进程间通信机制 41 4.1 信号机制 41 4.2 管道 42 4.3 套接字 44 4.3.1 System V的进程间通信机制 44 4.3.2 消息队列 44 4.3.3 信号量 45 4.3.4 共享存储区 47 第5章 PCI 49 5.1 PCI的地址空间 49 5.2 PCI配置头 50 5.3 PCI的I/O和存储地址空间 51 5.4 PCI-ISA桥 51 5.5 PCI-PCI 桥 51 5.5.1 PCI-PCI桥:PCI I/O和存储地址 空间的窗口 51 5.5.2 PCI-PCI桥:PCI配置周期和PCI 总线编号 52 5.6 Linux PCI初始化 53 5.6.1 Linux内核PCI数据结构 53 5.6.2 PCI设备驱动程序 53 5.6.3 PCI的BIOS函数 56 5.6.4 PCI修正过程 57 第6章 中断处理与设备驱动程序 60 6.1 中断与中断处理 60 6.1.1 可编程中断控制器 61 6.1.2 初始化中断处理数据结构 61 6.1.3 中断处理 62 6.2 设备驱动程序 63 6.2.1 测试与中断 64 6.2.2 直接存储器访问(DMA) 65 6.2.3 存储器 66 6.2.4 设备驱动程序与内核的接口 66 6.2.5 硬盘 69 6.2.6 网络设备 74 第7章 文件系统 77 7.1 第二个扩展文件系统EXT2 78 7.1.1 EXT2系统的inode节点 79 7.1.2 EXT2系统的超级块 80 7.1.3 EXT2系统的组描述符 80 7.1.4 EXT2系统的目录 81 7.1.5 在EXT2文件系统中查找文件 81 7.1.6 在EXT2文件系统中改变文件 的大小 82 7.2 虚拟文件系统 83 7.2.1 VFS文件系统的超级块 84 7.2.2 VFS文件系统的inode节点 84 7.2.3 注册文件系统 85 7.2.4 装配文件系统 85 7.2.5 在虚拟文件系统中查找文件 87 7.2.6 卸载文件系统 87 7.2.7 VFS文件系统的inode缓存 87 7.2.8 目录缓存 88 7.3 缓冲区缓存 88 7.3.1 bdflush内核守护进程 90 7.3.2 update进程 90 7.4 /proc文件系统 91 7.5 特殊设备文件 91 第8章 网络 92 8.1 TCP/IP网络概述 92 8.2 Linux中的TCP/IP网络层次结构 95 8.3 BSD套接字接口 96 8.4 INET的套接字层 97 8.4.1 创建BSD套接字 98 8.4.2 为INET BSD Socket绑定地址 99 8.4.3 建立INET BSD Socket连接 99 8.4.4 INET BSD Socket侦听 100 8.4.5 接受连接请求 100 8.5 IP层 100 8.5.1 套接字缓冲区 100 8.5.2 接收IP报文 101 8.5.3 发送IP报文 102 8.5.4 数据分片 102 8.6 地址解析协议 103 8.7 IP路由 104 第9章 内核机制与模块 107 9.1 内核机制 107 9.1.1 Bottom Half控制 107 9.1.2 任务队列 108 9.1.3 定时器 109 9.1.4 等待队列 110 9.1.5 自旋锁 110 9.1.6 信号量 110 9.2 模块 111 9.2.1 模块载入 112 9.2.2 模块卸载 113 第10章 处理器 115 10.1 X86 115 10.2 ARM 115 10.3 Alpha AXP处理器 115 第11章 Linux内核源代码 117 11.1 怎样得到Linux内核源码 117 11.2 内核源码的编排 117 11.3 从何处看起 118 第12章 Linux数据结构 120 附录A 有用的Web和FTP站点 138 附录B 词汇表 139 第二部分 Linux内核模块编程指南 致谢 前言 第1章 Hello, World 145 1.1 内核模块的Makefiles文件 146 1.2 多重文件内核模块 147 第2章 字符设备文件 149 第3章 /proc文件系统 158 第4章 把/proc用于输入 162 第5章 把设备文件用于输入 170 第6章 启动参数 182 第7章 系统调用 185 第8章 阻塞处理 190 第9章 替换printk 199 第10章 任务调度 202 第11章 中断处理程序 207 第12章 对称多处理 211 第13章 常见错误 212 附录A 2.0和2.2之间的差异 213 附录B 其他资源 214 附录C 给出你的评价 215 第三部分 Linux程序员指南 第1章 Linux操作系统 219 第2章 Linux内核 220 第3章 Linux libc包 221 第4章 系统调用 222 第5章 “瑞士军刀”:ioctl 223 第6章 Linux进程间通信 224 6.1 介绍 224 6.2 半双工Unix管道 224 6.2.1 基本概念 224 6.2.2 用C语言创建管道 225 6.2.3 简便方法 229 6.2.4 管道的原子操作 233 6.2.5 关于半双工管道需要注意的几个 问题 233 6.3 命名管道 234 6.3.1 基本概念 234 6.3.2 创建FIFO 234 6.3.3 FIFO操作 235 6.3.4 FIFO上的阻塞动作 236 6.3.5 SIGPIPE信号 237 6.4 系统V IPC 237 6.4.1 基本概念 237 6.4.2 消息队列 239 6.4.3 信号量 251 6.4.4 semtool:交互式信号量操作 程序 260 6.4.5 共享内存 267 第7章 声音编程 274 7.1 内部扬声器编程 274 7.2 声卡编程 274 第8章 字符单元图形 276 8.1 libc中的I/O函数 277 8.1.1 格式化输出 277 8.1.2 格式化输入 278 8.2 termcap库 278 8.2.1 前言 278 8.2.2 获得终端描述 279 8.2.3 查看终端描述 279 8.2.4 termcap权能 280 8.3 Ncurses简介 280 8.4 初始化 282 8.5 窗口 283 8.6 输出 284 8.6.1 格式化输出 285 8.6.2 插入字符/行 286 8.6.3 删除字符/行 286 8.6.4 方框和直线 287 8.6.5 背景字符 287 8.7 输入 288 8.8 选项 289 8.8.1 输出选项 289 8.8.2 输入选项 290 8.8.3 终端属性 291 8.8.4 使用选项 291 8.9 更新终端 292 8.10 视频属性与颜色 293 8.11 光标和屏幕坐标 294 8.12 滚动 294 8.13 小键盘 295 8.14 软标签 295 8.15 杂项 295 8.16 低级访问 296 8.17 屏幕转储 296 8.18 Termcap模拟 296 8.19 Terminfo函数 296 8.20 调试函数 297 8.21 Terminfo权能 297 8.21.1 布尔型权能 297 8.21.2 数值型权能 298 8.21.3 字符串型权能 299 8.22 [N]Curses函数概述 306 第9章 I/O端口编程 307 9.1 鼠标编程 307 9.2 调制解调器编程 308 9.3 打印机编程 308 9.4 游戏杆编程 308 第10章 把应用程序移植到Linux上 309 10.1 介绍 309 10.2 信号处理 309 10.2.1 SVR4、BSD和POSIX.1下 的信号 310 10.2.2 Linux信号选项 310 10.2.3 Linux下的信号 310 10.2.4 Linux支持的信号 311 10.3 终端I/O 311 10.4 进程信息和控制 311 10.4.1 kvm过程 312 10.4.2 ptrace和/proc文件系统 312 10.4.3 Linux下的进程控制 312 10.5 可移植条件编译 313 10.6 补充说明 314 附录 以字母顺序排列的系统调用 315 第四部分 Linux内核概念系统结构 摘要 323 前言 324 第1章 系统结构 325 1.1 系统概述 325 1.2 内核的目标 325 1.3 内核结构的概述 325 1.4 支持多个开发人员 327 1.5 系统数据结构 328 1.5.1 任务列表 328 1.5.2 内存映射 328 1.5.3 索引节点 328 1.5.4 数据连接 329 第2章 子系统的系统结构 330 2.1 进程调度程序系统结构 330 2.1.1 目标 330 2.1.2 模块 330 2.1.3 数据表达 331 2.1.4 依赖性、数据流和控制流 331 2.2 内存管理程序系统结构 331 2.2.1 目标 331 2.2.2 模块 331 2.2.3 数据表示 331 2.2.4 数据流、控制流和依赖性 332 2.3 虚拟文件系统系统结构 333 2.3.1 目标 333 2.3.2 模块 333 2.3.3 数据表示 333 2.3.4 数据流、控制流和依赖性 334 2.4 网络接口系统结构 334 2.4.1 目标 334 2.4.2 模块 334 2.4.3 数据表示 335 2.4.4 数据流、控制流和依赖性 335 2.5 进程间通信系统结构 335 第3章 结论 336 附录A 术语定义 337 附录B 参考文献 338 第五部分 Linux内核具体系统结构 摘要 341 第1章 前言 342 1.1 目标 342 1.2 Linux介绍 342 1.3 软件系统结构的背景知识 342 1.4 方法与途径 343 1.5 适用本书的读者 344 1.6 本部分的章节安排 344 第2章 系统结构 345 第3章 子系统结构 346 3.1 进程调度程序 346 3.1.1 目标 346 3.1.2 外部接口 346 3.1.3 子系统描述 346 3.1.4 数据结构 347 3.1.5 子系统结构 348 3.1.6 子系统依赖性 348 3.2 内存管理程序 348 3.2.1 目标 348 3.2.2 外部接口 349 3.2.3 子系统描述 349 3.2.4 数据结构 350 3.2.5 子系统结构 350 3.2.6 子系统依赖性 351 3.3 虚拟文件系统 352 3.3.1 目标 352 3.3.2 外部接口 352 3.3.3 子系统描述 353 3.3.4 设备驱动程序 353 3.3.5 逻辑文件系统 354 3.3.6 模块 354 3.3.7 数据结构 355 3.3.8 子系统结构 355 3.3.9 子系统依赖性 355 3.4 进程间通信 355 3.4.1 目标 355 3.4.2 外部接口 357 3.4.3 子系统描述 357 3.4.4 数据结构 358 3.4.5 子系统结构 359 3.4.6 子系统依赖性 359 3.5 网络接口 360 3.5.1 目标 360 3.5.2 外部接口 361 3.5.3 子系统描述 361 3.5.4 数据结构 362 3.5.5 子系统结构 363 3.5.6 子系统依赖性 363 第4章 结论 365 附录A 术语定义 366 附录B 参考文献 368 第六部分 附 录 附录A Linux文档工程拷贝许可证 372 附录B GNU通用公共许可证 374
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值