进程间的通信----信号量

目录

 

1.信号量的作用

2.信号量的本质

3.信号量如何实现同步与互斥

4.信号量的操作步骤


1.信号量的作用

信号量也是进程间的通信方式之一,更多的应用于实现进程间的同步与互斥。(进程/线程安全概念),保证进程间对临界资源的安全有序访问,同步保证的是有序,互斥保证的是安全。

同步:保证对临界资源访问的时序可控性

互斥:对临界资源同一时间的唯一访问性

多个进程同时操作一个临界资源的时候就需要通过同步与互斥机制来实现临界资源的安全访问。

2.信号量的本质

信号量的本质是具有一个等待队列的计数器(代表现在是否有资源使用)

3.信号量如何实现同步与互斥

当信号量没有资源可用时,这时候需要阻塞等待(当有资源的时候会打断这个阻塞)

a.对于同步来说:

只有信号量资源计数从0转变为1的时候,会同期其他进程打断阻塞等待,会操作临界资源,也就是说我们释放了资源(即计数器+1操作后)才能获取资源(即计数器-1操作)然后进行操作。

b.对于互斥来说:

信号量如果想要实现互斥,那么它的计数器只能是0或1,(一元信号量),即就是一个进程获取的计数器的资源,其他简称就没法获取了)也就代表了同一时间只有一个进程能够获得信号量,保证访问的安全。

进程在操作临界资源之前先获取信号量,判断是否可以对临界资源进行操作,如果没有信号量资源(计数器为0),则需要等待,当别人释放信号量资源后,信号量计数器变为1,则会唤醒等待的进程去重新获取信号量资源。【信号量计数器大于0,代表有资源可以获取,信号量计数器等于0,代表信号量没有资源,需要等待】

信号量作为进程间的通信方式,意味着大家都能访问到信号量,信号量实际上也是一个临界资源,当然信号量这个临界资源的操作是不会出问题的(因为信号量的操作是以个原子操作,是不可被打断的)

4.信号量的操作步骤

(1)semget:创建信号量

(2)semctl: SETVAL        SETALL:设置信号量的初值、

对临界资源操作之前先获取信号量(计数器减1操作)

对临界资源操作完毕之后需要西方的资源(计数器加1操作)

代码演示:

//这是一个基于信号量的互斥实现代码
//让一个进程打印A睡1000ms
//让另一个进程打印B睡1000ms然后在打印一个B
//查看结果是否有序
//通过同步与互斥实现



#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define IPC_KEY 0x12345678

 union semun {
     int              val;    /* Value for SETVAL */
     struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
     unsigned short  *array;  /* Array for GETALL, SETALL */
     struct seminfo  *__buf;   
    };

void sem_P(int id)
{
    struct sembuf buf;
    buf.sem_num =0;
    buf.sem_op= -1;
    buf.sem_flg=SEM_UNDO;
    
    semop(id, &buf,1);
}
    
void sem_V(int id)
{
    struct sembuf buf;
    buf.sem_num =0;
    buf.sem_op= 1;
    buf.sem_flg=SEM_UNDO;
    
    semop(id, &buf,1);
}
	
int main()
{
    int pid = -1;
    //1.创建或打开一个信号量
    int semid=semget(IPC_KEY,1,IPC_CREAT | 0664);
    if(semid < 0){
    perror("semget error");
    return -1;
    }
    //2.设置信号量初值,只能设置一次,不能重复设置
    //int semctl(int semid, int semnum, int cmd, ...);
    //semid 操作句柄
    //senum 指定要操作第几个信号量
    //	cmd   具体的操作
    //	SETVAL  设置单个信号量的初值
    //	SETALL  设置所有信号量的初值,semnum将被忽略
    //	IPC_RMID 
    //	...   是一个不定参数
    //	    比如要获取信号量的信息,那么第四个参数就是结构体
    //	    比如要设置信号量的值,那么放的就是指的联合体
    union semun val;
    val.val =1;
    semctl(semid ,0,SETVAL,val);
    pid = fork();
    if(pid < 0){
	perror("fork error");
    }else if(pid ==0){
	//打印A
	while(1){
	    //获取信号量
	    sem_P(semid);
	    printf("A");
	    fflush(stdout);
	    usleep(1000);
	    printf("A ");
	    fflush(stdout);
	    //释放信号量
	    sem_V(semid);
	}
    }else{
	//打印B
	
	while(1){
	sem_P(semid);
	    printf("B");
	    fflush(stdout);
	    usleep(100);
	    printf("B ");
	    fflush(stdout);
	    sem_V(semid);
	 }
    }
    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
线程中的信号量是一种同步机制,用于协调多个线程之的操作,保证它们按照指定方式进行。它的作用可以是控制线程的访问限制,限制某些操作的并发性,控制资源的分配等等。 在多线程编程中,信号量作用很重要,因为它可以使线程之协作并实现更高的并发性,提高程序的效率。Java中也提供了Semaphore类来实现信号量操作。 以下是一个Java代码示例,使用信号量实现对共享资源的并发访问控制: ``` import java.util.concurrent.Semaphore; public class SharedResource { // 声明一个信号量,限制同时访问共享资源的线程数 private Semaphore semaphore = new Semaphore(1); // 访问共享资源的方法 public void accessResource() { try { // 请求信号量,如果已经有线程在访问共享资源,则当前线程阻塞等待 semaphore.acquire(); // 访问共享资源 // ... } catch (InterruptedException e) { e.printStackTrace(); } finally { // 释放信号量,允许其他线程继续访问共享资源 semaphore.release(); } } } ``` 以上代码中,Semaphore类的构造函数传入的参数1表示限制同时访问共享资源的线程数为1。在accessResource()方法中,首先调用semaphore.acquire()方法请求信号量,如果有其他线程在访问共享资源,则当前线程会被阻塞等待;如果没有,则当前线程可以顺利访问共享资源。最后在finally块中调用semaphore.release()方法释放信号量,允许其他线程继续访问共享资源。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值