• Linux下多线程编程-信号量


    今天来谈谈线程的同步--信号量。

    首先来看看一些概念性的东西:

    如进程、线程同步,可理解为进程或线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B依言执行,再将结果给A;A再继续操作。

    所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回,同时其它线程也不能调用这个方法。按照这个定义,其实绝大多数函数都是同步调用(例如sin, isdigit等)。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。例如Window API函数SendMessage。该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。当对方处理完毕以后,该函数才把消息处理函数所返回的LRESULT值返回给调用者。

    在多线程编程里面,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何时刻,最多有一个线程访问,以保证数据的完整性。

    线程同步的方式和机制

    临界区、互斥量、事件、信号量四种方式

    临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphore)、事件(Event)的区别

    1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占。

    2、互斥量:采用互斥对象机制。 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享

    3、信号量:它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目

    4、事 件: 通过通知操作的方式来保持线程的同步,还可以方便实现对多个线程的优先级比较的操作

    这里我们重点讨论下信号量。

    • int sem_init(sem_t *sem, int pshared, unsigned int value);,其中sem是要初始化的信号量,为0时表示只能在当前进程的多个线程之间共享,pshared表示此信号量是在进程间共享还是线程间共享,value是信号量的初始值。
    • int sem_destroy(sem_t *sem);,其中sem是要销毁的信号量。只有用sem_init初始化的信号量才能用sem_destroy销毁。
    • int sem_wait(sem_t *sem);等待信号量,如果信号量的值大于0,将信号量的值减1,立即返回。如果信号量的值为0,则线程阻塞。相当于P操作。成功返回0,失败返回-1。
    • int sem_post(sem_t *sem); 释放信号量,让信号量的值加1。相当于V操作。

    上代码:

    /*

    线程信号量测试用例

    */

    #include <pthread.h>

    #include <unistd.h>

    #include <stdio.h>

    #include <stdlib.h>

    #include <semaphore.h>

    sem_t sem;

    int running = 1;

    void * producter_f(void *arg)

    {

        int semval = 0;

        while(running)

        {

            usleep(1);

            sem_post(&sem);

            sem_getvalue(&sem,&semval);

            printf("生产,总数量:%d ",semval);

        }

    }

    void * consumer_f(void *arg)

    {

        int semval = 0;

        while(running)

        {

            usleep(1);

            sem_wait(&sem);

            sem_getvalue(&sem,&semval);

            printf("消费,总数量:%d ",semval);

        }

    }

    int main()

    {

        pthread_t consumer_t;

        pthread_t producter_t;

        int err;

        sem_init(&sem,0,16);

        err = pthread_create(&producter_t,NULL,(void *)producter_f,NULL);

            printf("%d",err);

        pthread_create(&consumer_t,NULL,(void *)consumer_f,NULL);

        sleep(1);

        running = 0;

        pthread_join(producter_t,NULL);

        pthread_join(consumer_t,NULL);

        sem_destroy(&sem);

        return 0;

    }

  • 相关阅读:
    excel读取表,并将结果保存为键值对的字典列表;
    [置顶] MQ选型对比RabbitMQ RocketMQ ActiveMQ Kafka
    ActiveMQ持久化消息的三种方式
    getConstructor、getDeclaredConstructor区别
    JavaEE 保存文件获取绝对路径getResource("")和servletContext.getRealPath("/")
    Java中getResourceAsStream的用法
    Java 输出流中的flush方法
    Java之关闭流
    Java中的字节流、缓冲流
    java原生序列化和Kryo序列化性能比较
  • 原文地址:https://www.cnblogs.com/chase-wind/p/5394622.html
Copyright © 2020-2023  润新知