linux_信号量(详解)

一.信号量

1.1信号量的概述

信号量广泛用于进程或线程间的同步和互斥,信号量本质上是一个非负整数计数器,它被用来控制对公共资源的访问

编程时可根据操作信号量值的结果判断是否对公共资源具有访问的权限,当信号量大于0时,则可以访问,否则将阻塞

信号量又称之为PV操作,P V原语是对信号量的操作,一次P操作使信号量使信号量sem-1一次V操作使信号量sem+1,对于P操作,如果信号量的sem值小于等于0,则P操作就会阻塞,如果信号量的值大于0,才可以执行p操作进行减1

信号量主要用于进程或线程间的同步和互斥这两种情况

  1. 若用于互斥,几个进程(或线程)往往只设置一个信号量

  2. 若用于同步操作,往往会设置多个信号量,并且安排不同的初始值,来实现它们之间的执行顺序
    信号量用于互斥
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

信号量用于同步

二 信号量操作

2.1 信号量初始化

1. #include <semaphore.h>
2. int sem_init(sem_t *sem,int pshared,unsigned int value);
3. 功能:创建一个信号量并初始化它的值
4. 参数: sem:信号量地址  
		pshared:等于0,信号量在线程间共享;不等于0,信号量在进程共享。
		value:信号量的初始值。
5.返回值:成功返回0,失败返回-1

2.2 信号量的P操作

1. #include<semaphore.h>
2. int sem_wait(sem_t *sem);
3. 功能:将信号量的值减1,若信号量的值小于等于0,此函数会引起调用者阻塞
4. 参数:sem:信号量地址
5. 返回值:成功返回0,失败返回-1
 #include<semaphore.h>
2. int sem_trywait(sem_t *sem);
3. 功能:将信号量的值减1,若信号量的值小于等于0,则对信号量的操作失败,函数立即返回
4. 参数:sem:信号量地址
5. 返回值:成功返回0,失败返回-1

2.3 信号量的V操作

1. #include <semaphore.h>
2. int sem_post(sem_t *sem)	
3. 功能:执行v操作,执行一次,信号量的值加1
4. 参数:sem:信号量地址
5. 返回值:成功返回0,失败返回-1

2.4 获取信号量的计数值

1. #include <semaphore.h>
2. int sem_getvalue(sem_t *sem,int *sval);	
3. 功能:获取sem标识的信号量的值,保存在sval中
4. 参数:sem:信号量地址 sval:保存信号量值的地址
5. 返回值:成功返回0,失败返回-1

2.5 信号量的销毁

1. #include <semaphore.h>
2. int sem_destroy(sem_t *sem);	
3. 功能:删除sem标识的信号量,
4. 参数:sem:信号量地址 
5. 返回值:成功返回0,失败返回-1

三 信号量的使用

3.1 信号量实现互斥功能

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
// 通过信号量实现互斥操作
// 第一步:创建一个信号量

sem_t sem;

void printer(char *str)
{
//      第三步:执行p操作
//      由于使用信号量实现互斥,信号量初始值设置为1,则两个线程执行p操作
//      先执行p操作的线程继续执行,后执行p操作的先阻塞等待

        sem_wait(&sem);

        while(*str){
                putchar(*str);
                fflush(stdout);
                str++;
                sleep(1);
        }
//      第四步:执行v操作
        sem_post(&sem);
}

void *thr_fun1(void *arg)
{
        char *str1 = "change";
        printer(str1);
}


void *thr_fun2(void *arg)
{
        char *str2 = "word";
        printer(str2);
}

int main()
{

        pthread_t th1,th2;

//      第二步:初始化信号量
        sem_init(&sem,0,1);

        if(pthread_create(&th1,NULL,thr_fun1,NULL) != 0)
        {
                perror("fail to pthread_create");
                exit(1);
        }

        if(pthread_create(&th2,NULL,thr_fun2,NULL)  != 0)
        {
                perror("fail to pthread_create");
                exit(1);
        }

        pthread_join(th1,NULL);
        pthread_join(th2,NULL);
        printf("\n");
//      第五步
        sem_destroy(&sem);
        return 0;
}

执行结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.2 信号量实现同步功能

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
// 通过信号量实现同步操作
// 第一步:创建两个信号量

sem_t sem_p,sem_g;

char ch = 'a';

void *thr_g(void *arg)
{
        while(1)
        {
//              第四步:执行p功能
                sem_wait(&sem_g);
                ch++;
                sleep(1);
//              第六步:执行v操作
                sem_post(&sem_p);
        }
        pthread_exit(0);
}


void *thr_p(void *arg) // 打印ch的值
{
        while(1){
//              第三步执行p操作
                sem_wait(&sem_p);
                printf("%c",ch);
                fflush(stdout);
//              第五步执行V操作
                sem_post(&sem_g);
        }
        pthread_exit(0);

}

int main()
{

        pthread_t th1,th2;

//      第二步初始化信号量
        sem_init(&sem_p,0,1);
        sem_init(&sem_g,0,0);

        if(pthread_create(&th1,NULL,thr_p,NULL) != 0)
        {
                perror("fail to pthread_create");
                exit(1);
        }

        if(pthread_create(&th2,NULL,thr_g,NULL) != 0)
        {
                perror("fail to pthread_create");
                exit(1);
        }

        pthread_join(th1,NULL);
        pthread_join(th2,NULL);
        printf("\n");
//      第五步,销毁信号量
        sem_destroy(&sem_p);
        sem_destroy(&sem_g);
        return 0;
}
  
  • 15
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux共享内存是一种高效的进程间通信方式,它可以使多个进程共享同一块内存区域,从而避免了进程间的数据拷贝和通信的开销。下面是Linux共享内存的原理详解: 1.创建共享内存: 在Linux系统中,使用shmget()函数创建共享内存,该函数的原型如下: ``` int shmget(key_t key, size_t size, int shmflg); ``` 其中,key是共享内存的标识符,size是共享内存的大小,shmflg是共享内存的访问权限。shmget()函数返回一个共享内存的标识符,该标识符可以用于后续的共享内存操作。 2.映射共享内存: 使用shmat()函数将共享内存映射到进程的虚拟地址空间中,该函数的原型如下: ``` void *shmat(int shmid, const void *shmaddr, int shmflg); ``` 其中,shmid是共享内存的标识符,shmaddr是共享内存的映射地址,shmflg是共享内存的访问权限。shmat()函数返回一个指向共享内存映射区域的指针,该指针可以用于后续的共享内存操作。 3.使用共享内存: 通过共享内存映射的指针,进程可以直接访问共享内存中的数据,从而实现进程间的数据共享。需要注意的是,由于多个进程共享同一块内存区域,因此需要使用信号量等同步机制来避免数据竞争等问题。 4.撤销共享内存: 使用shmdt()函数将共享内存从进程的虚拟地址空间中撤销,该函数的原型如下: ``` int shmdt(const void *shmaddr); ``` 其中,shmaddr是共享内存的映射地址。shmdt()函数返回0表示成功,-1表示失败。 5.删除共享内存: 使用shmctl()函数删除共享内存,该函数的原型如下: ``` int shmctl(int shmid, int cmd, struct shmid_ds *buf); ``` 其中,shmid是共享内存的标识符,cmd是删除共享内存的命令,buf是共享内存的状态信息。shmctl()函数返回0表示成功,-1表示失败。 总结: Linux共享内存通过创建一块共享内存区域,使多个进程可以直接访问同一块内存,从而实现进程间的高效通信。需要注意的是,由于多个进程共享同一块内存区域,因此需要使用信号量等同步机制来避免数据竞争等问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值