多线程:
线程属于进程里面的基本调度单位,每一个进程都拥有自己的main(主线程)。
按照调度分为用户级线程和核心级线程
用户级线程作用:解决上下文的切换问题,调度算法和调度过程有用户来决定,
特点:用户级线程在运行时候不需要内核的支持。 缺点:无法发挥内核多处理器的优势。
核心级线程作用:允许不同线程按照同一个调度方式进行运行,能够发挥内核多处理器并发的优势,
实现一对一或者一对多。
学习阶段写的是用户级线程。
一个进程里面可以有多个线程,
也就是说多个线程控制同一个堆区、常量区和静态区域区域,都是公用一个地址空间。
这时候就会出现一个问题,由于线程共享了进程资源空间和地址,
因此,任何线程对资源操作会对其他线程的操作造成影响。
这时候就需要线程互斥的操作(请看后面的讲解)。
当创建线程的那一刻起,所有线程就是同时进行的(线程没有退出的情况下)。
讲个例子:
平常我们写的程序是从上到下运行的,并且只有一条路,遇到函数了,
就会先进函数,执行完了函数的代码,才回来主函数继续往下走,这就是单线程。
多线程就是有多条路,可以同时走多条路。通俗点说就是cpu可以同时运行多个函数(其实一条线程就是一个函数)。
创建线程函数:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
参数:
pthread_t *thread 线程id,指的是要创建的线程的id号
const pthread_attr_t *attr 用来修改线程属性,一般直接给NULL
void *(*start_routine) (void *) 函数指针,一般给自己写的函数的函数名
void *arg 传递给子线程的值
返回值:
成功:返回0
失败:不等于0
当主线程运行结束,所有的线程都会结束,这个时候需要阻塞函数,阻塞主线程保证其他线程正常运行。
主线程阻塞等待:
原型:int pthread_join(pthread_t thread,void **retval)
参数:pthread_t thread ---->线程ID
void **retval 接收目标线程退出时传出来的参数数据,一般NULL
返回值:成功,返回0
失败,非0
功能:等待另一线程结束---阻塞等待
主线程非阻塞等待:
函数原型:int pthread_detach(pthread_t thread);
函数形参:pthread_t thread -----线程ID
功能:等待线程退出---非阻塞等待 主要作用回收资源
返回值:
成功 0
失败 非0
根据需求选择阻塞或者非阻塞。
线程退出函数:
原型:void pthread_exit(void *retval)
参数:void *retval 传递给等待的线程的数据,一般情况直接给NULL
结束当前线程,并传递一个数据给同进程下等待该线程结束的另一个线程(创建他的线程)
return、exit()、pthread_exit()区别:
1.returen 是一个关键字,作用用来结束一个函数,return 不一定能够结束进程或线程
2.exit() 是一个函数,作用是用来结束一个进程,一定会结束进程下面多个线程,以及函数。
3.pthread_exit()是一个函数,作用是用来结束对应的线程,只能结束对应的线程,不能结束对应的进程。
线程互斥锁:
共享资源:多个线程可以同时访问。
临界资源:只可以同时被一个进程或者线程占用。
sudo apt-get install manpages-posix-dev安装相关的资源包
默认在man手册第3层 -f找不到
安装相关资源包之后才能查询到
核心:上锁和解锁操作。上锁:占用这个共享资源;解锁:释放占用的共享资源。
1.创建锁: int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
参数:
1).pthread_mutex_t *restrict mutex:自定义锁类型的变量
2).pthread_mutexattr_t *restrict attr:锁的属性 一般默认属性 给NULL
返回值:
0: 互斥锁创建成功
失败: 非0
2. 上锁:int pthread_mutex_lock(pthread_mutex_t *mutex);阻塞调用
3. 解锁: int pthread_mutex_unlock(pthread_mutex_t *mutex);
4. 销毁锁:int pthread_mutex_destroy(pthread_mutex_t *mutex);
线程互斥的目的是为了让线程有序,并且保护共享资源,最简单的例子就是:主线程打印奇数,子线程打印偶数。