IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 线程同步的四种方法 -> 正文阅读

[C++知识库]线程同步的四种方法

线程同步

线程同步,指的是一个线程发出某一功能调用时,在没有得到结果之前,该调用不返回。同时其它线程为保证数据一致性,不能调用该功能。
多个控制流,共同操作一个共享资源的情况,都需要同步

数据混乱原因
1.资源共享(独享资源不会)
2.调度随机(意味着数据访问会出现竞争)
3.线程间缺乏必要同步机制
restrict关键字
用来限定指针变量,被该关键字限定的指针变量所指向的内存操作,必须由本指针完成

互斥锁

概述

每个线程在对资源操作前都尝试先加锁,成功加锁才能操作,操作结束解锁。

但通过“锁”就将资源的访问变成互斥操作,而后与时间有关的错误也不会再产生了。
但,应注意:同一时刻,只能有一个线程持有该锁。

当A线程对某个全局变量加锁访问,B在访问前尝试加锁,拿不到锁,B阻塞。C线程不去加锁,而直接访问该全局变量,依然能够访问,但会出现数据混乱。

所以,互斥锁实质上是操作系统提供的一把“建议锁”(又称“协同锁”),建议程序中有多线程访问共享资源的时候使用该机制。但,并没有强制限定。
因此,即使有了mutex,如果有线程不按规则来访问数据,依然会造成数据混乱。

所需要的函数

pthread_mutex_t lock;//创建锁
pthread_mutex_init();//初始化锁
pthread_mutex_lock();//加锁
pthread_mutex_unlock();//解锁
pthread_mutex_destroy();//销毁锁

效果展示

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include<errno.h>
#include<unistd.h>
pthread_mutex_t mutex;//定义互斥锁
void*tfn(void*argv)
{
    srand(time(NULL));
    while(1)
    {
        pthread_mutex_lock(&mutex);//加锁
        printf("hello ");
        sleep(rand()%2);
        printf("world\n");
        pthread_mutex_unlock(&mutex);//解锁
        sleep(rand()%2);
    }
    return NULL;
}
int main()
{
    pthread_t tid;
    srand(time(NULL));
    int ret=pthread_mutex_init(&mutex,NULL);//初始化互斥锁
    if(ret!=0)
    {
        fprintf(stderr,"mutex_init_error:%s\n",strerror(ret));
        exit(1);
    }
    ret=pthread_create(&tid,NULL,tfn,NULL);
    if(ret!=0)
    {
        fprintf(stderr,"create error:%s\n",strerror(ret));
        exit(1);
    }
    while(1)
    {
        pthread_mutex_lock(&mutex);
        printf("HELLO ");
        sleep(rand()%2);
        printf("WORLD\n");
        pthread_mutex_unlock(&mutex);
        sleep(rand()%2);
    }
    pthread_join(tid,NULL);
    pthread_mutex_destroy(&mutex);//销毁互斥锁
    return 0;
}

此代码让子线程打印 hello 和 world,让主线程打印HELLO 和 WORLD
如果不加互斥锁的话,打印出来的大小写是不对应的如下图
在这里插入图片描述
当我们加入互斥锁效果如下
在这里插入图片描述

读写锁

概述

锁只有一把,以读方式给数据加锁--------读锁。以写方式给数据加锁---------写锁。
读共享,写独占。
写锁优先级高。

所需要的函数

pthread_rwlock_t rwlock;//创建读写锁
pthread_rwlock_init();//初始化锁
pthread_rwlock_rdlock();//加读锁
pthread_rwlock_wrlock();//加写锁
pthread_rwlock_trywrlock();//try锁
pthread_rwlock_unlock();//解锁
pthread_rwlock_destroy();//销毁锁多的时候,提高访问效率

效果展示

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
#include<errno.h>
int count;
pthread_rwlock_t rwlock;
void*th_write(void*argv)
{
    int t;
    int i=(int)argv;
    while(1)
    {
        pthread_rwlock_wrlock(&rwlock);
        t=count;
        usleep(2000000);
        printf("------write %d:%lu:count=%d ++count=%d\n",i,pthread_self(),t,++count);
        pthread_rwlock_unlock(&rwlock);
        usleep(10000);
    }
    return NULL;
}
void*th_read(void*argv)
{
    int i=(int)argv;
    while(1)
    {
        pthread_rwlock_rdlock(&rwlock);
        printf("------read %d:%lu:%d\n",i,pthread_self(),count);
        pthread_rwlock_unlock(&rwlock);
        usleep(20000);
    }
    return NULL;
}
int main()
{
    int i;
    pthread_t tid[8];
    pthread_rwlock_init(&rwlock,NULL);
    for(i=0;i<3;i++)
    {
        pthread_create(&tid[i],NULL,th_write,(void*)i);
    }   
    for(i=0;i<5;i++)
    {
        pthread_create(&tid[i+3],NULL,th_read,(void*)i);
    }
    for(i=0;i<8;i++)
    {
        pthread_join(tid[i],NULL);
    }
    pthread_rwlock_destroy(&rwlock);
}

执行结果
在这里插入图片描述

静态初始化条件变量

条件变量本身不是锁,但它也可以造成线程阻塞。通常与互斥锁配合使用。给多线程提供一个会合的场所。
条件变量是用来等待线程而不是上锁的,条件变量通常和互斥锁一起使用。条件变量之所以要和互斥锁一起使用,主要是因为互斥锁的一个明显的特点就是它只有两种状态:锁定和非锁定,而条件变量可以通过允许线程阻塞和等待另一个线程发送信号来弥补互斥锁的不足,所以互斥锁和条件变量通常一起使用。

当条件满足的时候,线程通常解锁并等待该条件发生变化,一旦另一个线程修改了环境变量,就会通知相应的环境变量唤醒一个或者多个被这个条件变量阻塞的线程。这些被唤醒的线程将重新上锁,并测试条件是否满足。一般来说条件变量被用于线程间的同步;当条件不满足的时候,允许其中的一个执行流挂起和等待。

常用函数

pthread_cond_t cond; //创建条件变量
pthread_cond_init();//初始化条件变量
pthread_cond_wait();//线程进入阻塞,等待信号被唤醒
pthread_cond_timedwait();//线程进入阻塞,一定时间后被唤醒
pthread_cond_signal();//满足条件后一次通知一个
pthread_cond_broadcast();//满足条件后一次通知多个
pthread_cond_destroy(); //销毁条件变量

举例样例参考
消费生产者问题

信号量

相当于初始化值为N的互斥量 。N值表示可以同时访问共享数据区的线程数

常用函数

  sem_t sem;
  int sem_init(sem_t *sem, int pshared, unsigned int value);
  //初始化
  //pshared传零用于线程间同步,传1用于进程和线程间同步
  //value也就是N
  int sem_wait(sem_t *sem);//加锁系信号量,信号量大于0,信号--操作,信号量等于0阻塞
  int sem_trywait(sem_t *sem);//try锁
  int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
 //限时尝试对信号进行加锁
  int sem_post(sem_t *sem);//解锁,将信号量++,同时唤醒阻塞在信号量上的线程
  int sem_destroy(sem_t *sem);//销毁信号量

以上六个函数都是成功返回0,失败返回-1同时设置error
举例样例参考
消费生产者问题

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-05 10:59:30  更:2022-05-05 10:59:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 20:39:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码