Linux线程(2)--线程同步与互斥

同步与互斥

同步:同步是不同任务之间的直接制约关系,是具有顺序性的执行,比如两个进程B依赖A执行完的数据, 因此只有执行了A才能执行B,其规定的是执行次序。
互斥:互斥是访问临界区的唯一性,是一种间接制约关系,同一时间只能有一个任务执行。比如在某一时刻只能有一个进程或者线程对一个文件进行写入。
临界区是访问临界资源的代码,临界资源是同一时间只能有一个任务访问的资源。这个任务可以是进程也可以是线程。

互斥量

在pthread库中提供了mutex互斥量可以是实现线程间的互斥访问临界资源
通过互斥量实现互斥锁对临界区的操作流程为
在进入临界区前先判断是否有其他线程正在访问(即是否有锁)如果没有则加锁进入临界区,否则进行阻塞直到被唤醒,之后在离开临界区后进行解锁,
互斥量接口:
初始化互斥量
函数原型:int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr);
函数参数:mutex是一个pthread_mutex_t 类型的互斥量地址,attr设置互斥量的属性,通常可采用默认属性,即可将 attr 设为 NULL
另外可以通过宏PTHREAD_MUTEX_INITIALIZER静态初始化互斥量
如pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
销毁互斥量
销毁信号量需要注意使用PTHREAD_ MUTEX_ INITIALIZER初始化的互斥量不需要销毁,用pthread_mutex_init初始化的互斥量因为是动态分配的所以需要销毁
函数原型:int pthread_mutex_destroy(pthread_mutex_t *mutex);
函数参数:互斥量地址
互斥量的加锁和解锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
加锁通过pthread_mutex_lock进行如果临界区已经被加锁(注意这个指同一个信号量)则阻塞等待否则返回0进入临界区,如果失败返回错误码
还有一个函数可以加锁int pthread_mutex_trylock(pthread_mutex_t *mutex);
调用该函数时,若互斥锁未加锁,则上锁,返回 0;若互斥锁已加锁,则函数直接返回失败,即 EBUSY并不会阻塞

条件变量

可以通过条件变量实现线程的同步操作,比如两个线程,一个线程给另一个线程提供数据,当第一个线程计算万数据将这个数据保存然后另一个线程访问这个数据,这个场景就需要通过条件变量加锁,首先线程1将数据填入这个数据单元线程2才可以访问,如果线程2在这个一直检查线程1是否完成势必会造成CPU资源浪费,因此加入条件变量,在线程2在等待条件满足前挂起,当线程1完成操作通知线程2(这个通知并不是真正给发信号还是其他,这个是的当完成后会调用pthread_cond_signal函数,修改条件变量同时激活阻塞队列中一个线程或者调用pthread_cond_broadcast修改条件变量激活阻塞队列中的所有线程)然后线称2被唤醒,此时线程2会访问这个单元,另外在这个过程中这个数据单元一个临界资源,在访问这个数据单元时需要加上互斥锁,多个线程同时修改这个数据单元会造成错误(前面的场景以因为只有两个任务假如线程1执行完就会结束,线程2再执行不会有同时访问临界资源的情况,这中是通过同步实现了临界资源的互斥访问因此这个情况可以省去互斥量),一般涉及到临界资源问题同步均伴随着互斥,因此条件变量需要一个互斥量来实现互斥锁pthread_cond_wait也需要两个参数一个条件变量一个互斥量
函数接口:
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
实现以下上面例子:

#include 
#include 
#include 

static int sum = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;

void * print(void *arg)
{
    pthread_detach(pthread_self());

    pthread_mutex_lock(&mutex);
    pthread_cond_wait(&cond, &mutex);

    printf("%d\n", sum);  //临界区

    pthread_mutex_unlock(&mutex);
}

void * count(void *arg)
{
    pthread_detach(pthread_self());
    sleep(1);
    pthread_mutex_lock(&mutex);
    sum = 1 + 1;
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);
}

int main()
{
    pthread_t print_, count_;
    pthread_create(&print_, NULL, print, NULL);
    pthread_create(&count_, NULL, count, NULL);

    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);

    sleep(10);

    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);
    return 0;
}

在这里插入图片描述

你可能感兴趣的:(Linux系统编程)