首页 > 编程语言 >C系统编程——线程的互斥与同步

C系统编程——线程的互斥与同步

时间:2024-10-30 20:19:05浏览次数:3  
标签:rwlock int 编程 互斥 线程 pthread mutex

        一般每个程序都会有多个线程,也不能确定每个线程所需要的资源都是独立的,如果有两个线程需要同一个资源,且其中一个使用后却将其给释放掉了,那另一个就会得不到资源导致系统卡死,这也便是死锁,这是我们就新加了新的知识:互斥与同步来预防这类问题的发生。

1.概念

        一个进程中线程间共享着大量的数据,互斥与同步的机制在程序中便无可避免。

2.互斥锁

(1)特性

        互斥锁也叫互斥量,属于pthread线程库中的互斥同步技术,对应的控制操作就是加锁后不能再继续加锁,除非解锁后。

(2)编程使用

//1.声明初始化互斥锁
    pthread_mutex_t lock;
    pthread_mutex_init(&lock,NULL);
//pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
//2.加锁/获取锁
    int pthread_mutex_lock(pthread_mutex_t *mutex);
    int pthread_mutex_trylock(pthread_mutex_t *mutex);
//3.访问共享资源
//4.解锁/释放锁
    int pthread_mutex_unlock(pthread_mutex_t *mutex);
//5.不再使用时销毁锁
    int pthread_mutex_destroy(pthread_mutex_t *mutex);

例程:

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

char *data[5]={"hello","world","bob","jack","tom"};
//声明互斥锁
pthread_mutex_t lock;
//线程函数1
void *task(void *arg)
{
    //加锁
    pthread_mutex_lock(&lock);
    sleep(1);
    printf("task thread id=%lu\n",pthread_self());
    //访问共享资源
    for(int i=0;i<5;i++){
        sleep(1);
        printf("task:%d:%s\n",i,data[i]);
    };
    //解锁
    pthread_mutex_unlock(&lock);
    pthread_exit(NULL);//退出线程
};
//线程函数2
void *task1(void *arg)
{
    //加锁
    pthread_mutex_lock(&lock);
    sleep(1);
    printf("task thread id=%lu\n",pthread_self());
    //访问共享资源
    for(int i=0;i<5;i++){
        sleep(1);
        printf("task1:%d:%s\n",i,data[i]);
    };
    //解锁
    pthread_mutex_unlock(&lock);
    pthread_exit(NULL);//退出线程
};
int main()
{
    //初始化互斥锁
    pthread_mutex_init(&lock,NULL);
    //1.创建id
    pthread_t id1,id2;
    //2.创建线程
    pthread_create(&id1,NULL,task,NULL);
    printf("线程创建成功,id=%lu\n",id1);
    pthread_create(&id2,NULL,task1,NULL);
    printf("线程创建成功,id=%lu\n",id2);
    for(int i=50;i>30;i--){
        sleep(1);
    }
    //销毁锁
    pthread_mutex_destroy(&lock);
    return 0;
}

3.读写锁

(1)概念

        由于互斥锁对读写操作直接进行互斥控制,多个线程经常性同时读写的情况下效率较差,因为对共享资源的读操作无需互斥,可以同时进行,为此添加了读写锁。

        读写锁对加锁进行了区分,读操作前加读锁,写操作前加写锁。读锁属于共享锁,写锁属于互斥锁。

(2)编程方法

//1.声明初始化读写锁
    pthread_rwlock_t rwlock;
    pthread_rwlock_init(&rwlock,NULL);
//2.加锁
//加读锁
    int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_tryrwlock(pthread_rwlock_t *rwlock);
//加写锁
    int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
//3.访问共享资源
//4.解锁
    int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
//5.销毁读写锁
    int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

参考例程:

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

char *data[5]={};
int size=0;
//声明读写锁
pthread_rwlock_t rwlock;
//写线程函数
void *write_task(void *arg)
{
    //加写锁
    pthread_rwlock_wrlock(&rwlock);
    //写共享资源
    data[size]=(char *)arg;
    sleep(1);
    size++;
    //解锁
    pthread_rwlock_unlock(&rwlock);
    pthread_exit(NULL);//退出线程
};
//读线程函数
void *read_task(void *arg)
{
    //加读锁
    pthread_rwlock_rdlock(&rwlock);
    //读共享资源
    for(int i=0;i<size;i++){
        printf("%lu:%s\n",pthread_self(),data[i]);
        sleep(1);
    };
    //解锁
    pthread_rwlock_unlock(&rwlock);
    pthread_exit(NULL);//退出线程
};
int main()
{
    //初始化读写锁
    pthread_rwlock_init(&rwlock,NULL);
    //创建id
    pthread_t id1,id2,id3,id4,id5;

    pthread_create(&id1,NULL,write_task,"BOB");
    pthread_create(&id2,NULL,write_task,"TOM");
    pthread_create(&id3,NULL,write_task,"JACK");
    sleep(2);
    pthread_create(&id4,NULL,read_task,NULL);
    pthread_create(&id5,NULL,read_task,NULL);

    for(int i=0;i<10;i++)
    sleep(1);
    //销毁锁
    pthread_rwlock_destroy(&rwlock);
    return 0;
}

4.信号量(POSIX信号量)

(1)概念

        线程中的信号量和进程中的信号量原理是相同的,都是一个计数器,用来控制访问共享资源的最大并行线程数。

        工作原理:设置初始计数(共享资源个数),每来一个任务访问计数-1(P操作),每退出一个任务计数+1(V操作),当计数值为0时不允许任务访问,直到计数值重新大于0为止。

        POSIX信号量不属于线程库的范畴,使用时需要包含头文件——semaphore.h

        如果初始计数值为1,效果等同于互斥锁。

        POSIX信号量分为无名信号量和有名信号量。

 (2)无名信号量的编程使用

标签:rwlock,int,编程,互斥,线程,pthread,mutex
From: https://blog.csdn.net/2303_76896902/article/details/143372278

相关文章

  • 条件编译、多文件编程、结构体
    条件编译条件编译可以在编译的时候从几组语句中选择一组编译而忽略其他组,#ifdef/#ifndef...#else...#endif这个结构可以根据一个宏名称是否被定义过从两组语句中选择一组编译,最开始的预处理指令都应该从两个里选择一个,不论选择哪一个都应该在后面写一个宏名称。如果最开始的......
  • 16.1 并发编程基础——Java多线程
    16.1并发编程基础——Java多线程16.1.1 引言Java语言的一个重要特点是内在支持多线程的程序设计。多线程的程序设计具有广泛的应用。线程的概念来源于操作系统进程的概念。进程是一个程序关于某个数据集的一次运行。也就是说,进程是运行中的程序,是程序的一次运行活动。线......
  • 【GiraKoo】线程本地存储(Thread Local Storage, TLS)
    【技术分享】线程本地存储(ThreadLocalStorage,TLS)在项目开发中,遇到了关于TLS相关的问题。为了了解该机制的用途,在微软的官网查找了一些资料。本文参考官方文档,简单介绍一下TLS的用途与使用方法。微软官方文档链接一、简介线程本地存储(TLS),可以使多个线程,通过TlsGetValue函......
  • 【GiraKoo】C++多线程消息分发架构
    【开源需求】C++多线程消息分发架构项目【gi_messager】在多线程环境中,为每个线程提供独立的消息队列MessageLoop。注:主线程默认自动创建消息队列。MessageLoopCenter提供MessageLoop的查询功能。能够获得指定MessageLoop的句柄。同一个MessageLoop可以绑定多个......
  • Java编程语言:从入门到精通
    Java是一种广泛使用的高级编程语言,由SunMicrosystems在1995年发布,后来被Oracle公司收购。Java以其“一次编写,到处运行”(WriteOnce,RunAnywhere)的理念而闻名,成为企业级应用开发、Android应用开发和大数据处理等领域的重要工具。二、Java的发展历程1991年:SunMicros......
  • C++编程语言:从基础到高级
    C++是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,支持过程化、面向对象和泛型编程。C++由丹麦计算机科学家BjarneStroustrup于1979年在贝尔实验室开始开发,最初作为C语言的扩展,称为“CwithClasses”。1983年,正式更名为C++。C++以其高效、灵活......
  • 编程语言的绘图库有哪些?
    Python中的Matplotlib库特点与应用场景:Matplotlib是Python中最常用的绘图库之一,它提供了广泛的绘图功能,能够创建各种类型的静态、动态图表,包括折线图、柱状图、饼图、散点图等。适用于数据可视化、科学计算可视化、统计图表制作等众多领域。示例代码-绘制简单折线图:i......
  • 【JavaEE】【多线程】定时器
    目录一、定时器简介1.1Timer类1.2使用案例二、实现简易定时器2.1MyTimerTask类2.2实现schedule方法2.3构造方法2.4总代码2.5测试一、定时器简介定时器:就相当于一个闹钟,当我们定的时间到了,那么就执行一些逻辑。1.1Timer类Java的标准库中提供了在java.ut......
  • 多线程编程ExecutorService用法
    以下内容均来自ChatGPT提供的示例,用于自学ExecutorService是Java中用于管理和控制线程池的接口,通常用来简化多线程编程。它提供了一组方法,允许我们在异步任务执行完毕后关闭线程池、调度任务等操作。以下是几个常见的使用场景和示例代码:1.使用ExecutorService执行简单任务......
  • 实验2 类和对象_基础编程1
    实验任务1头文件#pragmaonce#include<string>//类T:声明classT{ //对象属性、方法public: T(intx=0,inty=0);//普通构造函数 T(constT&t);//复制构造函数 T(T&&t);//移动构造函数 ~T();//析构函数 voidadjust(intratio); voiddispla......