#include "head.h"int rfd, wfd;
long size;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 定义互斥锁void* first(void *arg)
{// 定位文件指针前加锁pthread_mutex_lock(&mutex);lseek(rfd, 0, SEEK_SET);lseek(wfd, 0, SEEK_SET);pthread_mutex_unlock(&mutex);char buf[4096]; // 使用缓冲区提高性能ssize_t bytes;for (long i = 0; i < size / 2; ){bytes = read(rfd, buf, sizeof(buf));if (bytes <= 0) break;write(wfd, buf, bytes);i += bytes;}printf("前半部分拷贝完毕.....");pthread_exit(NULL);
}void* last(void *arg)
{// 定位文件指针前加锁pthread_mutex_lock(&mutex);lseek(rfd, size / 2, SEEK_SET);lseek(wfd, size / 2, SEEK_SET);pthread_mutex_unlock(&mutex);char buf[4096];ssize_t bytes;for (long i = size / 2; i < size; ){bytes = read(rfd, buf, sizeof(buf));if (bytes <= 0) break;write(wfd, buf, bytes);i += bytes;}printf("后半部分拷贝完毕.....");pthread_exit(NULL);                                                  
}int main(int argc, const char *argv[])
{// 打开源文件和目标文件rfd = open("./xiaoxin.bmp", O_RDONLY);if (rfd < 0) {perror("open source file failed");exit(1);}wfd = open("./cp_xiaoxin.bmp", O_WRONLY | O_CREAT | O_TRUNC, 0664);if (wfd < 0) {perror("open target file failed");close(rfd);exit(1);}// 计算文件大小size = lseek(rfd, 0, SEEK_END);pthread_t tid1, tid2;// 创建线程并检查错误if (pthread_create(&tid1, NULL, first, NULL)){perror("create thread1 failed");close(rfd);close(wfd);exit(1);}if (pthread_create(&tid2, NULL, last, NULL)) {perror("create thread2 failed");close(rfd);close(wfd);exit(1);}// 等待线程结束pthread_join(tid1, NULL);pthread_join(tid2, NULL);// 销毁互斥锁(可选)pthread_mutex_destroy(&mutex);close(rfd);close(wfd);return 0;
}核心要点:线程
一、线程基础
-  线程概念 - 引入目的:减少进程切换的资源开销,提高效率。
- 定义:线程是进程内任务执行的最小单位,共享进程资源(内存、文件等)。
- 并发 vs 并行: - 并发:单核 CPU 通过时间片轮询模拟“同时”执行多任务。
- 并行:多核 CPU 真正同时执行多任务。
 
- 上下文切换:CPU 在不同线程间切换时保存/恢复资源的过程。
 
-  线程 vs 进程(面试重点) - 资源:进程资源独立,线程共享进程资源。
- 单位:进程是资源分配的最小单位,线程是执行的最小单位。
- 稳定性:进程更稳定,线程更轻量但易出错。
- 通信:线程直接共享数据(需同步),进程需 IPC 机制。
 
二、线程函数
-  创建线程: pthread_create- 功能:创建新线程。
- 参数: - thread:存储新线程 ID。
- attr:线程属性(默认- NULL)。
- start_routine:线程入口函数(- void* func(void*))。
- arg:传递给线程函数的参数。
 
- 返回值:成功返回 0,失败返回错误码(如 EAGAIN、EINVAL)。
 
-  终止线程: pthread_exit- 功能:结束当前线程,可返回结果(void* retval)。
- 注意:主线程终止会导致所有分支线程终止。
 
- 功能:结束当前线程,可返回结果(
-  连接线程: pthread_join- 功能:阻塞等待指定线程结束,回收资源。
- 参数: - thread:目标线程 ID。
- retval:接收线程返回值(二级指针)。
 
 
-  分离线程: pthread_detach- 功能:设置线程为分离态,资源由系统自动回收。
- 注意:分离后无法使用 pthread_join。
 
-  取消线程: pthread_cancel- 功能:发送取消请求。
- 状态控制: - pthread_setcancelstate:设置是否可取消(- ENABLE/DISABLE)。
- pthread_setcanceltype:设置取消类型(- DEFERRED/ASYNCHRONOUS)。
 
 
三、同步与互斥
-  基本概念 - 临界资源:多线程共享的变量/文件等。
- 临界区:访问临界资源的代码段。
- 互斥:保证同一时间仅一个线程访问临界资源(无序)。
- 同步:在互斥基础上控制线程执行顺序。
 
-  互斥锁( pthread_mutex_t)- 使用步骤: - 初始化:pthread_mutex_init或静态初始化PTHREAD_MUTEX_INITIALIZER。
- 加锁:pthread_mutex_lock(阻塞)或pthread_mutex_trylock(非阻塞)。
- 解锁:pthread_mutex_unlock。
- 销毁:pthread_mutex_destroy。
 
- 初始化:
- 死锁风险:未正确释放锁可能导致死锁。
 
- 使用步骤: 
-  信号量( sem_t)与条件变量(pthread_cond_t)- 信号量:通过计数器控制资源访问数量。
- 条件变量:用于线程间条件通知(需搭配互斥锁)。
 
四、实践示例
-  多线程文件拷贝 - 目标:两个线程分别拷贝文件的前半部分和后半部分。
- 关键函数:lseek定位文件偏移,read/write读写数据。
- 注意:需通过同步机制避免读写冲突(如互斥锁)。
 
-  银行存取款模拟 - 场景:存款线程与取款线程操作全局变量 money。
- 实现:使用互斥锁保护 money的读写操作。
 
- 场景:存款线程与取款线程操作全局变量 
五、作业与练习
- 思维导图:总结线程概念、函数、同步机制。
- 无 sleep的多线程文件拷贝:通过同步机制(如条件变量)替代sleep控制线程执行顺序。
常见问题
- 线程共享资源:全局变量、文件描述符等需同步保护。
- 分离态 vs 结合态:分离态线程资源由系统回收,结合态需手动 pthread_join。
- 取消点:printf、sleep等函数隐含取消点,可触发线程终止。


