云计算百科
云计算领域专业知识百科平台

Linux入门DAY30(多线程、进程间通信、网络编程与数据库)

上一篇我们梳理了 Linux 文件编程,包含标准 IO、文件 IO、目录操作、framebuffer 帧缓冲与日志模块。本篇继续往下学习多线程高级、IPC 进程间通信、Socket 网络编程、简单数据库开发,把 Linux 应用开发四大模块补全。

回顾前文要点速览

文件编程两大体系:

  • 标准 IO:C 库函数,FILE*文件流,自带缓冲区,可移植性强;
  • 文件 IO(系统调用):open/read/write/close,文件描述符 fd,无用户层缓冲,贴近内核;
  • 拓展:目录 IOopendir/readdir、mmap 内存映射操作/dev/fb0帧缓存、日志文件封装。
  • 进程:资源分配最小单位;线程:CPU 调度最小单位。 进程拥有完整独立虚拟地址空间;同一进程内多个线程共享堆、全局数据、代码段,每个线程私有栈。


    一、多线程高级知识点

    1. 线程基础函数回顾

    int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
    void *(*start_routine) (void *), void *arg);

    编译必须加 -pthread 参数。

    线程退出、资源回收
  • pthread_exit(void *retval):线程主动退出,可以携带返回值;
  • pthread_join(pthread_t thread, void **retval):阻塞等待回收线程,类似进程 wait;如果不 join,会产生线程僵尸,内存泄漏;
  • pthread_detach(pthread_t thread):线程分离。分离之后线程结束自动释放资源,不需要 join 回收。适合后台工作线程。
  • ⚠️注意:主线程如果return / exit(),整个进程所有线程全部销毁;主线程调用pthread_exit(),主线程退出,其他子线程可以继续运行。

    2. 线程同步:互斥锁 pthread_mutex_t

    多线程共享全局变量,会产生竞态条件(数据混乱)。互斥锁用来保护共享资源,保证同一时间只有一个线程访问临界资源。

    核心 API:

    pthread_mutex_init(); //初始化锁
    pthread_mutex_lock(); //加锁,拿不到就阻塞
    pthread_mutex_unlock(); //解锁
    pthread_mutex_destroy();//销毁锁

    使用范式:

    pthread_mutex_t mutex;
    //临界区开始
    pthread_mutex_lock(&mutex);
    //操作共享全局变量
    pthread_mutex_unlock(&mutex);
    //临界区结束

    3. 条件变量 pthread_cond_t

    互斥锁解决 “互斥访问”;条件变量解决线程等待 / 唤醒,生产者消费者模型必备。 常用接口:

    pthread_cond_init();
    pthread_cond_wait(); //释放锁并阻塞等待条件,被唤醒后重新获取锁
    pthread_cond_signal(); //唤醒一个等待线程
    pthread_cond_broadcast();//唤醒全部等待线程
    pthread_cond_destroy();

    经典模型:生产者往队列放数据,条件变量发信号;消费者cond_wait阻塞,收到信号读取队列。

    4. 线程属性

    • 分离属性:创建线程的时候设置分离属性,等价于pthread_detach;
    • 栈大小:可以自定义线程栈空间,嵌入式开发常用。

    进程 VS 线程完整对比

    表格

    对比项进程线程
    调度单位 资源分配最小单位 CPU 调度最小单位
    内存空间 完全独立虚拟地址空间 共享进程资源,仅栈私有
    创建开销 大,拷贝页表、内存 很小,仅分配线程栈
    崩溃影响 一个进程崩溃互不干扰 一个线程崩溃,整个进程全部退出
    通信方式 IPC 管道、消息队列、共享内存、socket 直接读写全局变量,配合锁与条件变量

    坑点总结:

  • fork 之后子进程只会复制调用 fork 的那一个线程,其他线程全部消失;多线程程序尽量避免 fork。
  • 锁忘记释放 → 死锁;加锁顺序不一致也会死锁。

  • 二、进程间通信 IPC

    进程虚拟地址相互隔离,不能直接访问对方内存,必须借助内核提供 IPC 机制。

    常见 IPC 方式:

  • 管道 pipe:血缘进程通信(父子进程),半双工,字节流;
  • 有名管道 FIFO:无血缘关系进程也可以通信;
  • 消息队列:内核维护消息缓冲区,带类型数据块;
  • 共享内存 shm:多个进程映射同一块物理内存,速度最快 IPC,但是没有同步机制,必须配合信号量 / 锁;
  • 信号量 sem:做同步互斥,不传递业务数据;
  • 信号 signal:异步通知,传递简单事件;
  • Socket:可以本机进程通信,也支持跨主机网络通信。
  • 1. 匿名管道 pipe

    int pipe(int fd[2]);
    // fd[0]读端,fd[1]写端

    管道特点:

    • 数据单向流动;读端关闭,写触发 SIGPIPE 信号;写端关闭,read 返回 0;
    • 只适用于有亲缘关系进程。

    2. 信号 signal

    信号是软件中断。kill -l查看全部信号。 signal() / sigaction()注册信号处理函数。

    注意:信号处理函数内部只允许调用可重入函数,不要使用 printf/malloc 等不安全函数。

    3. 共享内存(最高速 IPC)

    shmget() //创建/获取共享内存id
    shmat() //映射到本进程虚拟地址
    shmdt() //解除映射
    shmctl() //控制、删除共享内存

    共享内存没有自带同步,一定要搭配信号量或者互斥锁,否则多进程同时写会乱数据。


    三、Linux 网络编程 Socket

    一切皆文件,socket 也是一种文件描述符,可以用 read/write 读写。

    TCP(面向连接,可靠流式)服务器开发流程

  • socket() 创建套接字,返回 fd;
  • bind() 绑定 IP 和端口号;
  • listen() 设置监听,开启被动连接;
  • accept() 阻塞等待客户端连接,返回新通信 socket fd;
  • read/write 和客户端收发数据;
  • close 关闭套接字。
  • TCP 客户端流程:

  • socket();
  • connect () 向服务器发起连接;
  • read/write 收发;
  • close。
  • UDP(无连接,数据报)

    不需要 connect、listen、accept; 使用sendto()发送,recvfrom()接收,自带对端地址。

    字节序大坑

    网络统一使用大端字节序;主机可能小端。 转换函数: htons() htonl() ntohs() ntohl() h‑host 主机,n‑network 网络,s‑short,l‑long。

    常用结构体:struct sockaddr_in IPv4 地址结构。

    IO 模型(重点面试)

  • 阻塞 IO(默认):accept、read 没有数据就卡住;
  • 非阻塞 IO:socket 设置 O_NONBLOCK,没有数据立刻返回‑1;
  • IO 多路复用:select /poll/epoll。
  • epoll 是 Linux 高性能网络核心,高并发服务器基石。

    简单区分:

    • select:文件描述有上限;
    • poll:无上限,但每次全部遍历;
    • epoll:事件驱动,只返回就绪 fd,百万并发首选。

    服务器架构:单进程 epoll;多进程 fork;多线程。


    四、Linux 下数据库编程 SQLite

    嵌入式常用轻量数据库 SQLite,文件型数据库,不需要独立服务进程。

    核心 API:

  • sqlite3_open() 打开数据库文件;
  • sqlite3_exec() 直接执行 SQL 语句(建表、增删改);
  • sqlite3_prepare_v2() 预处理语句,查询数据;
  • 回调函数或者 step 函数获取查询结果;
  • sqlite3_close()关闭数据库。
  • 基础 SQL 语句:

    CREATE TABLE user(id INTEGER PRIMARY KEY, name TEXT);
    INSERT INTO user(name) VALUES("zhangsan");
    SELECT * FROM user;
    UPDATE user set name="lisi" where id=1;
    DELETE FROM user where id=1;

    编译链接需要 -lsqlite3。

    使用场景:本地配置存储、日志记录、嵌入式设备本地数据管理。


    五、整套 Linux 应用开发知识总框架

  • 文件编程:标准 IO、系统调用 IO、目录、mmap 帧缓冲、日志;
  • 多任务:进程 fork、僵尸 / 孤儿进程、exec;线程 pthread、锁、条件变量;
  • IPC 进程间通信:管道、消息队列、共享内存、信号;
  • Socket 网络编程:TCP/UDP,字节序,IO 多路复用 epoll;
  • SQLite 数据库,持久化结构化数据。
  • 学习实操建议

  • 文件:自己实现 cp 工具、日志模块、framebuffer 画点;
  • 进程:fork 创建子进程,wait 回收,练习 execl 调用 ls 命令;
  • 线程:写生产者消费者模型,练习互斥锁 + 条件变量;
  • 网络:写简单 TCP 回显服务器,再改造 epoll 多路复用;
  • SQLite:写一个简单用户信息增删改查程序。
  • 小结

    进程和线程是多任务的两种实现,线程更轻量适合 CPU 密集、IO 密集并发;进程隔离性强,稳定性更高。进程间通信手段很多,追求速度优先选共享内存,跨机器通信就用 Socket 网络编程;结构化持久存储选择 SQLite 数据库。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Linux入门DAY30(多线程、进程间通信、网络编程与数据库)
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!