多线程|线程同步和线程安全

1.多线程

线程有一套完整的与其有关的函数库调用,它们中的绝大多数函数名都以 pthread_ 开头。为了使用这些函数库调用,我们必须定义宏 _REENTRANT,在程序中包含头文件pthread.h,并且在编译程序时需要用选项 -lpthread 来链接线程库。

-L指定库的存储位置

-l指定库的名称

并行:特殊的并发运行,同步运行,需要多个处理器

并发:在一段时间内交替执行,单个处理器就可以进行

注意:有多个处理器不一定是并行也可以是并发。

2.线程同步

一个进程中的所有线程共享同一个地址空间和诸如打开的文件之类的其他资源。一个线程对资源的任何修改都会影响同一个进程中其他线程的环境。因此,需要同步各种线程的活动,以便它们互不干涉且不破坏数据结构。例如,如果两个线程都试图同时往一个双向链表中增加一个元素,则可能会丢失一个元素或者破坏链表结构。

线程同步指的是当一个线程在对某个临界资源进行操作时,其他线程都不可以对这个资源进行操作,直到线程完成操作, 其他线程才能操作,也就是协同步调,让线程按预定的先后次序进行运行。 线程同步的方法有四种:互斥锁、信号量、条件变量、读写锁。

2.1互斥锁

int pthread_mutex_init(pthread_mutex_t *mutex,pthread_mutexattr_t 
*attr);//attr:锁的属性,不需要传空即可
int pthread_mutex_lock(pthread_mutex_t *mutex);//加锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);//解锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);//销毁锁
//注意,互斥锁mutex都需要传地址,因为要改变它;

2.2信号量

int sem_init(sem_t *sem, int pshared, unsigned int value);
//信号量的初始化
//sem_init()在sem指向的地址初始化未命名的信号量。这个value参数指定信号量的
初始值(第三个参数)。
//pshared:设置信号量是否在进程间共享,Linux不支持,一般给0; (非0为共享)
int sem_wait(sem_t *sem);
//P操作,wait表示等待,相当于是等待获取资源,那么就是P操作
int sem_post(sem_t *sem);
//V操作
int sem_destroy(sem_t *sem);
//销毁信号

2.3条件变量

#include <pthread.h>
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t
*attr);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t
*mutex);
//将条件变量添加到等待队列中,阻塞,等待被唤醒;第一个参数是条件变量的地址,第二个参
数是互斥锁;
//也就是说条件变量往往伴随着互斥锁的使用;
int pthread_cond_signal(pthread_cond_t *cond); //唤醒单个线程
int pthread_cond_broadcast(pthread_cond_t *cond); //唤醒所有等待的
线程
int pthread_cond_destroy(pthread_cond_t *cond);//销毁条件变量

2.4读写锁

读者和读者共享资源,读者和写者互斥;写者和写者互斥,写者和读者互斥.

#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t
*rwlock,pthread_rwlockattr_t *attr);
//第一个参数是锁的地址,第二个参数是锁的属性
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);//加读锁
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);//加写锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);//解锁,不管加的
是读锁还是写锁,都用unlock解锁
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);//销毁

3.线程安全(重点)

线程安全即就是在多线程运行的时候,不论线程的调度顺序怎样,最终的结果都是一样的、正确的。那么就说这些线程是安全的。

要保证线程安全需要做到:

1) 对线程同步,保证同一时刻只有一个线程访问临界资源。

2)在多线程中使用线程安全的函数(可重入函数),所谓线程安全的函数指的是:如果一个函数能被多个线程同时调用且不发生竟态条件,则我们程它是线程安全的。

一般情况下:函数有_r的版本就是该函数的可重入版本。

可重入函数:重入即表示重复进入,首先它意味着这个函数可以被中断,其次意味着它除了使用自己栈上的变量以外不依赖于任何环境(包括static),这样的函数就是purecode(纯代码)可重入,可以允许有该函数的多个副本在运行,由于它们使用的是分离的栈,所以不会互相干扰。如果确实需要访问全局变量(包括static),一定要注意实施互斥手段。可重入函数在并行运行环境中非常重要,但是一般要为访问全局变量付出一些性能代价。

注意:多线程中,一定要小心线程使用全局(静态)变量,因为所有线程会共享这些变量,线程最好使用自己的局部变量。

线程也有ID(Linux实现线程的方式独特,内核没有多线程的概念,将线程当作进程看待,主线程PID就是进程PID,其他线程PID+1)

查看方法:ps -eLf

猜你喜欢

转载自blog.csdn.net/weixin_53472334/article/details/132327893