多线程编程—线程的同步与互斥

A . 线程一、线程的同步与互斥同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。 1、线程(进程)同步的主要任务答:在引入多线
摘要由CSDN通过智能技术生成

A . 线程

一、线程的同步与互斥

同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。

互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。

1、线程(进程)同步的主要任务

答:在引入多线程后,由于线程执行的异步性,会给系统造成混乱,特别是在急用临界资源时,如多个线程急用同一台打印机,会使打印结果交织在一起,难于区分。当多个线程急用共享变量,表格,链表时,可能会导致数据处理出错,因此线程同步的主要任务是使并发执行的各线程之间能够有效的共享资源和相互合作,从而使程序的执行具有可再现性。

2、线程(进程)之间的制约关系?

当线程并发执行时,由于资源共享和线程协作,使用线程之间会存在以下两种制约关系。

(1)间接相互制约。一个系统中的多个线程必然要共享某种系统资源,如共享CPU,共享I/O设备,所谓间接相互制约即源于这种资源共享,打印机就是最好的例子,线程A在使用打印机时,其它线程都要等待。

(2)直接相互制约。这种制约主要是因为线程之间的合作,如有线程A将计算结果提供给线程B作进一步处理,那么线程B在线程A将数据送达之前都将处于阻塞状态。

    间接相互制约可以称为互斥,直接相互制约可以称为同步,对于互斥可以这样理解,线程A和线程B互斥访问某个资源则它们之间就会产个顺序问题——要么线程A等待线程B操作完毕,要么线程B等待线程操作完毕,这其实就是线程的同步了。因此同步包括互斥,互斥其实是一种特殊的同步。

3、临界资源和临界区

    在一段时间内只允许一个线程访问的资源就称为临界资源或独占资源,计算机中大多数物理设备,进程中的共享变量等待都是临界资源,它们要求被互斥的访问。每个进程中访问临界资源的代码称为临界区。

二、引入互斥锁 (mutex)

1、多线程的冲突举例

我们知道,多个线程同时访问共享数据时,可能会产生冲突。比如两个线程都要把某个全局变量增加1,这个操作在某平台需要三条指令完成:
1> 从内存读变量值到寄存器
2>寄存器的值加1
3>将寄存器的值写回内存
假设两个线程在多处理器平台上同时执行这三条指令,则可能导致下图所示的结果,最后变量只加了一次而非两次。

这里写图片描述

数据二义性产生原因:不同的线程访问同一份临界资源,其次线程的操作不是原子操作。

2、解决多线程的冲突问题 —-引入互斥锁

    对于多线程的程序,访问冲突的问题是很普遍的,解决的办法是引入互斥锁(Mutex,Mutual Exclusive Lock),获得锁的线程可以完成“读-修改-写”的操作,然后释放锁给其它线程,没有获得锁的线程只能等待而不能访问共享数据,这样“读-修改-写”三步操作组成一个原子操作,要么都执行,要么都不执行,不会执行到中间被打断,也不会在其它处理器上并行做这个操作。

三. 互斥锁的相关函数

Mutex用pthread_mutex_t类型的变量表示。

1>定义一把锁

pthread_mutex_t lock;

2>互斥锁lock的初始化

(1). 如果lock是局部变量—可用初始化函数pthread_mutex_init初始化。

**int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);

返回值:成功返回0,失败返回错误号。

(2). 如果lock是静态或全局变量—可用 PTHREAD_MUTEX_INITIALIZER 初始化 ,相当于用pthread_mutex_init初始化并且attr参数为NULL。

3>加锁与解锁

int pthread_mutex_trylock(pthread_mutex_t* mutex);//非阻塞式加锁
int pthread_mutex_lock(pthread_mutex_t* mutex)//阻塞式加锁
int pthread_mutex_unlock(pthread_mutex_t* mutex)//解锁

如果一个线程既想获得锁,又不想挂起等待,可以调用pthread_mutex_trylock,如果Mutex已经被另一个线程获得,这个函数会失败返回EBUSY,而不会使线程挂起等待。

Mutex的两个基本操作lock和unlock是如何实现的呢?
假设Mutex变量的值为1表示互斥锁空闲,这时某个进程调用lock可以获得锁,而Mutex的值为0表示互斥锁已经被某个线程获得,其它线程再调用lock只能挂起等待。

4>销毁锁资源

int pthread_mutex_destroy(pthread_mutex_t* mutex);

返回值:成功返回0,失败返回错误号。

5>解决多线程的冲突问题测试代码:

mutex.c:

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

int a=0;// 定义全局变量
//加入互斥锁解决线程冲突
pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;//定义全局锁并初始化

void* pthread_add(void* val)
{
    int i=5000;
    while(i--)
    {
        pthread_mutex_lock(&lock); //加锁
        int tmp=a;
     // printf("%d\n",a);
        a=tmp+1;
        pthread_mutex_unlock(&lock);// 解锁
    }
    return (void*)0;
}

int main()
{
    pthread_t tid1;
    pthread_t tid2;
    pthread_create(&tid1,NULL,pthread_add,NULL);
    pthread_create(&tid2,NULL,pthread_add,NULL);
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    printf("%d\n",a);
    pthread_mutex_destroy(&lock);//销毁锁资源

    return 0;
}

运行结果:

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值