Linux多线程–同步、互斥

发布于 2019-10-28  47 次阅读


互斥

一份资源在同一时刻只能被一个进程或线程访问。

同步

进程按一定的顺序访问临界资源,同步强调的是协同,一般都在互斥的前提下,但在有些场景下也不需要互斥。

互斥量

互斥量,也叫互斥锁。是实现同步重要工具。

在线程访问共享资源前对互斥量进行设置(加锁),在线程访问共享资源结束后释放互斥量(解锁)。
通过加锁解锁,可以将原来的分多步的操作变成一个“原子”操作。

系统只会在执行完“锁内”的代码后,才可能会被切去执行其他线程。

在一个线程占用锁资源时(钥匙),任何其他再试图申请同一份锁资源的线程,都会被阻塞。直到当前线程释放该锁资源。

正规来说,对互斥量进行加锁以后,任何其他试图再次对互斥量加锁的线程都会被阻塞,直到当前线程释放该互斥锁。
在互斥锁被释放时,所有因为该锁被阻塞的线程都会变成可运行状态,第一个变为运行的线程就可以对互斥量加锁(获取钥匙),其他线程就会看到锁资源依然被占用,只能回去再次等待。
在这种方式下,我们可以达到一个时刻只有一个线程可以向前执行,并且多线程时会按照一定的顺序进行协同。
这种互斥锁也可以理解为二元信号量

互斥锁操作函数

  • 首先互斥锁的数据类型为pthread_mutex_t。
  • 创建互斥锁
    1. int pthread_mutex_init(pthread_mutex_t* restrict mutex,const pthread_mutexattr_t* restrict attr)
    2. pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  • 加锁
    int pthread_mutex_lock(pthread_mutex_t *mutex);
  • 解锁
    int pthread_mutex_unlock(pthread_mutex_t *mutex);
  • 当一个线程已经占用锁资源时,其他线程就会因为得不到锁资源而被阻塞。如果一个线程不想被阻塞的话,可以使用pthread_mutex_trylock尝试对互斥量进行加锁,如果调用时互斥量处于未锁住状态,那么pthread_mutex_trylock将会锁住该互斥量,不会出现阻塞直接返回0。否则就会trylock失败,返回EBUSY。
  • 摧毁锁
    int pthread_mutex\_destroy(pthread_mutex_t *mutex);

死锁

出现的原因

  • 同一线程申请了两次同样的锁资源
  • 两个线程互相申请彼此锁占有的锁资源

产生的条件

  • 请求与保持
  • 互斥属性
  • 不可剥夺,抢占
    • 剥夺:Linux进程线程是可剥夺的(当时间片结束,系统强行剥夺,运行其他程序)
      抢占:当一个进程或线程比正在运行的进程或线程优先级高,则可发生抢占,Linux支持。
  • 环路等待

实例:

无锁的错误版本

#include<stdio.h>
#include<pthread.h>
int count = 0;

void* thread_run(void* arg)
{
    int i = 0;
    int num = 5000;
    int val = 0;
    while(i < num)
    {
        val = count;

        printf("val : %d\n",val);
        count = val + 1;
        i++;
    }
    return NULL;
}

int main()
{
    printf("thread\n");
    pthread_t tid1;
    pthread_t tid2;
    pthread_create(&tid1,NULL,thread_run,NULL);
    pthread_create(&tid2,NULL,thread_run,NULL);
    //pthread_create()
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    printf("count: %d\n",count);


    return 0;
}

count:4832

加锁之后:

#include<stdio.h>
#include<pthread.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

int count = 0;

void* thread_run(void* arg)
{
    int i = 0;
    int num = 5000;
    int val = 0;
    while(i < num)
    {       
        pthread_mutex_lock(&mutex);
        val = count;
        printf("val : %d\n",val);
        count = val + 1;
        i++;
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main()
{
    printf("thread\n");
    pthread_t tid1;
    pthread_t tid2;
    pthread_create(&tid1,NULL,thread_run,NULL);
    pthread_create(&tid2,NULL,thread_run,NULL);
    //pthread_create()
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    pthread_mutex_destroy(&mutex);
    printf("count: %d\n",count);


    return 0;
}

 

喜欢这篇文章吗,不妨分享给朋友们吧!

科学是第一生产力