Linux操作系统-信号量

Posted TangguTae

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux操作系统-信号量相关的知识,希望对你有一定的参考价值。

信号量也属于一种进程间通信的机制,与其他的进程间通信不同,信号量不是用来传输数据的,而是用来进程间同步与互斥。除此之外,信号量还可以实现线程间的互斥

信号量是什么?

信号量的本质是一个计数器。

一个信号量是由一个内核维护的整数,它的值被限制在大于等于0。对信号量可以进行以下操作:

1、将信号量设置一个值。

2、在信号量当前值的基础上加上一个数量(V操作)。

3、在信号量当前值的基础上减去一个数量(P操作)。

4、当信号量的值为0时,会被阻塞。

既然是计数器,那么其中的count也是临界资源,所以PV操作必须得是原子的。

Linux下信号量的P.V操作如何保证其原子性_weixin_34402090的博客-CSDN博客

P操作

相当于count--;

P()
        lock();
        if(count)
            count--;
        else
            wait(); // 阻塞
        unlock();

V操作

相当于count++

V()
        lock();
        count++;
        if(count<=0)
            wakeup();//唤醒
        unlock();

注意:V操作的唤醒进程或者线程是不确定的,即具体是哪个进程或者线程被唤醒并允许递减这个信号量是不确定的,仅仅是一个同步机制,而不是一个排队机制。


POSIX信号量

头文件 semaphore.h

1、初始化一个信号量

sem_init函数

sem_t 声明一个信号量;

sem_init函数使用value中指定的值对sem指向的信号量进行初始化。通俗一点就是给信号量中的count值赋一个初值。

第二个参数要注意

pshared表明这个信号量是在线程间共享还是在进程间共享。

如果pshared=0,这个信号量会在调用进程中的线程间进行共享。此时这个信号量应该为临界资源,让线程都可以看到。

如果pshared=1,这个信号量在进程间共享。此时需要放在内存共享区,即共享内存或者mmap映射区域。

2、P操作

sem_wait()函数

sem_wait函数就是让sem指向的信号量的值减1.

如果信号量的当前值大于0,则sem_wait立即返回。如果信号量的当前值小于0,那么sem_wait会阻塞到信号量的值大于0为止。

 

3、V操作

sem_post函数

sem_post函数就是将sem指向的信号量的值+1。

如果在sem_post调用之前信号量的值为0,并且其他某个进程(线程)正在因为等待递减这个信号量而阻塞,那么该进程(线程)会被唤醒。

4、销毁一个信号量

sem_destroy函数

 

sem必须被sem_init初始化才能被销毁

只有在不存在进程或线程在等待一个信号量时才能够安全销毁这个信号量。


用信号量实现线程互斥

用信号量来代替互斥锁mutex。

思想:将信号量设置为0,1两个状态,这样就可以达到互斥锁的效果。

//一个简单的抢票程序
#include <iostream>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>                                                 
using namespace std;
class myclass

private:
    sem_t mtx;
    int ticket = 5000;
public:
    myclass()
    
        sem_init(&mtx, 0, 1);//设置大小为1即和锁一样的特点
    
    ~myclass()
    
        sem_destroy(&mtx);
    
    void P()//封装一下PV操作的函数
    
        sem_wait(&mtx);
    
    void V()
    
        sem_post(&mtx);
    
    void Run()
    
        pthread_t tid[4];
        for (int i = 0; i < 4; i++)//创建四个线程
            pthread_create(tid + i, nullptr, Routine, this);
        for (int i = 0; i < 4; i++)
            pthread_join(tid[i], nullptr);
    
    static void* Routine(void* arg)
    
        myclass* ptr = (myclass*)arg;
        while (1)
        
            ptr->P();
            if (ptr->ticket > 0)
            
                usleep(1000);
                cout << "i am thread " << pthread_self() << ", i get tikcet num is " << ptr->ticket << endl;
                (ptr->ticket)--;
                ptr->V();
            
            else
            
                ptr->V();
                break;
            
        
        return nullptr;
    
;
int main()

    myclass mc;
    mc.Run();
    return 0;

以上是关于Linux操作系统-信号量的主要内容,如果未能解决你的问题,请参考以下文章

有N个并发进程,设s是用于互斥信号量,其初值s=3,当s=-2时,意味着( ),执行一个 P(s)操作

(王道408考研操作系统)第二章进程管理-第三节5:用信号量实现进程互斥同步和前驱关系

有n个并发进程,设s是用于互斥的信号量,其初值s=3,当s=-2时意味啥

Linux内核自旋锁

Linux设备驱动之并发控制

经典进程同步问题