#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
等函数隐含取消点,可触发线程终止。