Linux从入门到开发实战(C/C++)Day10-线程
1.概念:
线程是一个函数,是os调度的基本单位
Linux内核在2.2版本之前,是没有线程的概念,只有有限个进程(4096)
在2.4版本中,有了线程的概念,而且可以有无数个
主线程一般默认main函数
分支线程一般是被创建的线程
一个进程中至少有一个线程,同一进程中的线程共享进程的所有资源(全局变量)
多个线程可以用一个线程函数,函数中的局部变量是每个线程独有的(不共用)
2.如何创建并启用线程
#include <pthread.h>
pthread_create 创建线程(man pthread_create)
int pthread_create(
pthread_t *thread, //线程id,作为返回参数
const pthread_attr_t *attr, //线程属性
void *(*start_routine) (void *), //线程函数
void *arg //线程函数参数
);
Compile and link with -pthread.
//程序中使用了这个函数,生成时要链接库 gcc *.c -l pthread
线程传参
参数为void* 注意类型转换即可
线程结束:
自然结束
线程函数结束
主线程结束
主线程结束时会结束掉分支线程
用pthread_exit
与exit函数类似
其他线程发送信号给线程
pthread_kill
其他线程结束线程
pthread_cancel
获取线程返回值
pthread_join 阻塞函数,直到获取的线程结束,这个函数才返回,一般是用它等待某线程结束
3.临界数据
多个线程同时运行,都可以访问到的数据叫做临界数据
多个线程同时访问临界数据后,导致临界数据脏(结果不对)
4.线程同步
通过各种方式让并发执行的线程不同时访问同一块区域
原子锁 atomic_add(老版本的有,现在不支持了)特性:不可分割
自旋锁 pthread_spinlock_init
一直在循环等待
互斥锁建立锁消耗多,当线程阻塞的时候不会一直循环,处于阻塞情况下不消耗资源
自旋锁建立锁消耗资源少,当线程阻塞的时候一直循环检查锁是否可用,处于阻塞情况下消耗资源
互斥锁适用于阻塞时间长的情况
自旋锁适用于阻塞时间短的情况
pthread_spinlock_t
pthread_spinlock_init
pthread_spinlock_lock
pthread_spinlock_unlock
pthread_spinlock_destory
也可以和条件变量联用让线程相对均匀分配
信号量(旗语)
读写锁 pthread_rwlock_init
有两把锁,一把 读 锁,一把 写 锁,读写、写写相斥,读读相容
pthread_rwlock_t 创建
pthread_rwlock_init 初始化
pthread_rwlock_wrlock 加写锁
pthread_rwlock_rdlock 加读锁
pthread_rwlock_unlock 解锁
pthread_rwlock_destory 销毁
互斥量 pthread_mutex_init
相互排斥,某个线程加了锁,其他线程在解锁前都阻塞
可能某个线程很久都抢不到加锁权(不能均匀分配cpu时间片)
如果希望多个线程相对公平,就要和条件变量一起使用
条件变量 pthread_cond_init
pthread_cond_t 创建
pthread_cond_init 初始化
pthread_cond_wait 等待信号(阻塞式)
pthread_cond_signal 向某个线程发送信号
pthread_cond_bordcast 向所有线程发送信号
pthread_cond_destroy 销毁信号
通用编程模型:
1.创建锁/变量
2.初始化
3.使用
加锁
解锁
4.销毁锁
死锁:线程卡死
死锁产生必须要满足的四点:
1)请求且保持
2)不可撤销
3)不可摧毁
4)循环请求
粒度:一把锁锁住的范围
粒度小 锁越多 越灵活 消耗的资源越多
粒度大 锁越少 越不灵活 消耗的资源越少
// pthread
void *func(void *arg)
{
int n = 0;
while (1)
{
printf("分支线程:%d\n", n--);
sleep(2);
}
}
void _pthread()
{
int n = 0;
pthread_t pt = 0;
printf("pt: %u\n", pt);
pthread_create(&pt, NULL, func, NULL);
while (1)
{
printf("主线程:%d\n", n++);
sleep(2);
}
}
// 1.创建互斥量
pthread_mutex_t mutex;
int num = 0;
void f_mutex()
{
for (size_t i = 0; i < 1000; i++)
{
// 3.使用互斥量前加锁
pthread_mutex_lock(&mutex);
num++;
// 用完解锁
pthread_mutex_unlock(&mutex);
}
}
void _pthread_mutex()
{
pthread_t t1, t2;
/// 2.初始化互斥量
pthread_mutex_init(&mutex, NULL);
pthread_create(&t1, NULL, f_mutex, NULL);
pthread_create(&t2, NULL, f_mutex, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("%d\n", num);
// 4.销毁互斥量
pthread_mutex_destroy(&mutex);
}
//
// 互斥量与条件变量一起用
pthread_mutex_t mutex_1;
pthread_cond_t cond_1;
void f1()
{
while (1)
{
pthread_mutex_lock(&mutex_1);
pthread_cond_wait(&cond_1, &mutex_1);
printf("===线程1===\n");
sleep(1);
pthread_mutex_unlock(&mutex_1);
}
}
void f2()
{
while (1)
{
pthread_mutex_lock(&mutex_1);
pthread_cond_wait(&cond_1, &mutex_1);
printf("---线程2---\n");
sleep(1);
pthread_mutex_unlock(&mutex_1);
}
}
void f3()
{
while (1)
{
pthread_mutex_lock(&mutex_1);
pthread_cond_wait(&cond_1, &mutex_1);
printf("+++线程3+++\n");
sleep(1);
pthread_mutex_unlock(&mutex_1);
}
}
void _pthread_mutexAndCond()
{
pthread_t t1, t2, t3;
/// 2.初始化
pthread_mutex_init(&mutex_1, NULL);
pthread_cond_init(&cond_1, NULL);
pthread_create(&t1, NULL, f1, NULL);
pthread_create(&t2, NULL, f2, NULL);
pthread_create(&t3, NULL, f3, NULL);
while (1)
{
pthread_cond_signal(&cond_1);
sleep(1);
}
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
// 4.销毁
pthread_mutex_destroy(&mutex_1);
pthread_cond_destroy(&cond_1);
}