线程的同步与互斥

本文介绍了多线程编程中解决资源竞争的两种技术——互斥量Mutex和信号量Semaphore。详细讲解了互斥锁的初始化、上锁、解锁及销毁,以及信号量的P、V操作,展示了它们在实现线程同步和互斥中的应用。
摘要由CSDN通过智能技术生成

进行多线程编程,因为无法知道哪个线程会在哪个时候对共享资源进行操作,因此让如何保护共享资源变得复杂,通过下面这些技术的使用,可以解决

线程之间对资源的竞争:

1. 互斥量Mutex

2. 信号灯Semaphore

3. 条件变量Conditions

mutex互斥锁线程控制

1、互斥锁是用一种简单的加锁方法来控制对共享资源的原子操作。

2、互斥锁只有两种状态,也就是上锁和解锁,可以把互斥锁看作某种意义上的全局变量。

3、在同一时刻只能有一个线程掌握某个互斥锁,拥有上锁状态的线程能够对共享资源进行操作。若其他线程希望上锁一个已经被上锁的互斥锁,则该线程就会挂起,直到上锁的线程释放掉互斥锁为止。

互斥锁的基本操作:

一、互斥锁初始化:pthread_mutex_init()

函数的作用:初始化互斥锁

函数的原型:int pthread_mutex_init(pthread_mutex_t  *restrict mutex,const pthread_mutexaddr  *attr);

函数的参数:mutex:互斥锁;

                          mutexattr:PTHREAD_MUTEX_INITIALIZER:快速互斥锁;

返回值:成功为0;出错<0;

 

二、互斥锁上锁:pthread_mutex_lock()

函数的作用:对互斥锁上锁;

函数的原型:pthread_mutex_lock(pthread_mutex_t *mutex);

返回值:0;出错:-1;

 

互斥锁判断上锁:pthread_mutex_trylock(pthread_mutex_t  *mutex)

互斥锁解锁:pthread_mutex_unlock(pthread_mutex_t *mutex)

消除互斥锁:pthread_mutex_destroy(pthread_mutex_t  *mutex)

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

pthread_mutex_t mutex;

void fun1(void)
{
    int i;

    pthread_mutex_lock(&mutex);

    for(i = 0;i < 5;i++)
    {
        printf("this is fun1\n");
        sleep(1);
    }

    pthread_mutex_unlock(&mutex);

}

void fun2(void)
{
    int i;

    pthread_mutex_lock(&mutex);

    for(i = 0;i < 5;i++)
    {
        printf("this is fun2\n");
        
    }
    pthread_mutex_unlock(&mutex);
}

int main()
{
    pthread_t id1,id2;

    pthread_mutex_init(&mutex,NULL);

    pthread_create(&id1,NULL,(void *)fun1,NULL);
    pthread_create(&id2,NULL,(void *)fun2,NULL);
    pthread_join(id1,NULL);
    pthread_join(id2,NULL);
    
    pthread_mutex_destroy(&mutex);

    return 0;
}

该段程序成功实现了线程1上锁时线程2无法运行,待线程1 完全运行结束后,线程2才继续运行;

信号量线程控制

信号量也就是操作系统中所用到的PV原子操作,它广泛用于进程或线程间的同步与互斥。

信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。

PV原子操作是对整数计数器信号量sem的操作。

一次P操作使sem减一,而一次V操作使sem加一。

进程(或线程)根据信号量的值来判断是否对公共资源具有访问权限。

当信号量sem的值大于等于零时,该进程(或线程)具有公共资源的访问权限;

相反,当信号量sem的值小于零时,该进程(或线程)就将阻塞直到信号量sem的值大于等于0为止。PV原子操作主要用于进程或线程间的同步和互斥这两种典型情况。

对于互斥,其基本流程图如下:


关于同步,其操作流程图如下图所示:

 


信号量的线程控制

Linux实现了POSIX的无名信号量,主要用于线程间的互斥与同步。以下主要介绍几个常见函数。

1sem_init()

函数作用:用于创建一个信号量,并初始化它的值。

函数原型:int sem_init(sem_t  *sem,int psharee,unsigned  int value);

函数参数:sem:信号量指针;

          pshared:0;

          value:信号量的初始值;

返回值:成功0,出错-1

头文件:#include <semaphore.h>

2sem_wait()sem_trywait()都相当于P操作,在信号量大于零时它们都能将信号量的值减一,两者的区别在于若信号量小于零时,sem_wait()将会阻塞进程,而sem_trywait()则会立即返回。

sem_wait()

函数原型:int sem_wait(sem_t  *sem);

          int sem_trywait(sem_t  *sem);

          int sem_post(sem_t  *sem);v操作

          int sem_getvalue(sem_t  *sem);

          int sem_destroy(sem_t  *sem);

函数参数:sem:信号量指针;

返回值:成功0,出错-1

 

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

sem_t sem1,sem2;

void *myThread1(void)
{
    int i;

    sem_wait(&sem1);

    for(i = 0;i < 3;i++)
    {
        printf("hello hello.\n");
        sleep(1);

    }
    sem_post(&sem2);

}

void *myThread2(void)
{
    int i;

    sem_wait(&sem2);

    for(i = 0;i < 5;i++)
    {
        printf("world world.\n");
        sleep(1);

    }
    sem_post(&sem1);


}
int main()
{
    int i = 0;
    int ret = 0;
    pthread_t id1,id2;

    sem_init(&sem1,0,0);
    sem_init(&sem2,0,1);

    ret = pthread_create(&id1,NULL,(void *)myThread1,NULL);
    if(ret)
    {
        printf("creat pthread error!\n");
        return 1;

    }

    ret = pthread_create(&id2,NULL,(void *)myThread2,NULL);
    if(ret)
    {
        printf("creat pthread error!\n");
        return 1;

    }
    pthread_join(id1,NULL);
    pthread_join(id2,NULL);
    
    sem_destroy(&sem1);
    sem_destroy(&sem2);

    return 0;
}

 

 

 





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值