信号量的简单使用

信号量是多任务操作系统中用来实现多个进程或线程之间同步于互斥的,在操作系统中使用PV操作实现信号量的操作。

在本例中,首先创建一个子进程,然后利用信号量实现控制父子进程的运行顺序:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sem.h>
#include <sys/ipc.h>

/*为了得到更好的观察效果,设置延时*/
#define DELAY_TIME 3 

int init_sem(int sem_id,int init_value);
int del_sem(int sem_id);
int sem_p(int sem_id);
int sem_v(int sem_id);

/*semctl函数在对信号量进行操作时,最后一个参数需要一个union结构的共同体,一般操作系统自定义
 * 而这个共同体在本系统(CentOS 6.3)上没有没有定义*/
union semun
{
	int val;
	struct semid_ds *buf;
	unsigned short *array;
};

int main(void)
{
	pid_t ret;
	int sem_id;

/*调用semget函数创建信号量*/
	sem_id = semget(ftok(".",'a'),1,IPC_CREAT | 0666);
/*调用自定义的函数init_sem初始化信号量*/
	init_sem(sem_id,1);
/*创建子进程*/
	ret = fork();
	if( ret == -1 )
	{
		perror("fork");
		exit(1);
	}
/*在子进程中*/
	else if(ret == 0 )
	{
		printf("Child process will wait for seconds......\n");
/*子进程P操作抢占资源*/
		sem_p(sem_id);
/*休眠3秒,得到更好的实验效果*/
		sleep(3);
		printf("The returned value is %d in the child process(PID = %d)\n",ret,getpid());
/*子进程V操作释放资源*/
		sem_v(sem_id);
	}
/*在父进程中*/
	else
	{
/*为了保证子进程先得到资源,让父进程睡眠1秒*/
		sleep(1);
/*在子进程释放了资源后,申请资源*/
		sem_p(sem_id);
		printf("The returned value is %d int the parent process(PID = %d)\n",ret,getpid());
/*释放资源*/
		sem_v(sem_id);
/*删除信号量*/
		del_sem(sem_id);
	}
	
	return 0;
}

/*自定义函数初始化信号量*/
int init_sem(int sem_id,int init_value)
{
	union semun sem_union;

	sem_union.val = init_value;
/*初始化信号量为init_value*/
	if( semctl(sem_id,0,SETVAL,sem_union) == -1 )
	{
		perror("semctl");
		return -1;
	}
	return 0;
}

/*自定义函数删除信号量*/
int del_sem(int sem_id)
{
	union semun sem_union;

/*删除信号量*/
	if( semctl(sem_id,0,IPC_RMID,sem_union) == -1 )
	{
		perror("semctl");
		return -1;
	}
	return 0;
}

/*自定义函数进行P操作*/
int sem_p(int sem_id)
{
/*调用系统定义的结构体创建对象
 * semop函数是对这个结构体制定操作方式的*/
	struct sembuf sem_b;

/*单个信号的编号应该为0*/
	sem_b.sem_num = 0;
/*定义操作,减1,也就是P操作*/
	sem_b.sem_op = -1;
/*指定标志,系统将自动释放系统中残留的信号量*/
	sem_b.sem_flg = SEM_UNDO;

/*semop函数利用结构体进行P操作*/
	if( semop(sem_id,&sem_b,1) == -1 )
	{
		perror("P operation");
		return -1;
	}
	
	return 0;
}

/*定义函数进行V操作*/
int sem_v(int sem_id)
{
	struct sembuf sem_b;

	sem_b.sem_num = 0;
	sem_b.sem_op = 1;
	sem_b.sem_flg = SEM_UNDO;

	if( semop(sem_id,&sem_b,1) == -1 )
	{
		perror("V operation");
		return -1;
	}
	
	return 0;
}

执行结果:


可以看到是子进程先退出,父进程后退出,而fork出来的父子进程的执行顺序是不定的!

在上面的例子中,我们先让父进程睡眠了1秒,如果不这么做的话,由于fork的执行顺序不定,可能是父进程先抢占了资源,然后很快的子进程又申请,这时子进程就会报错:invalid argument,如下图:



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FreeRTOS中的信号量是一种用于任务间同步和资源共享的机制。它通过控制任务对共享资源的访问,避免了竞争条件和资源冲突。 要使用FreeRTOS中的信号量,首先需要创建一个信号量对象。可以使用`xSemaphoreCreateBinary()`或`xSemaphoreCreateCounting()`函数来创建二进制信号量或计数信号量。创建信号量后,可以使用`xSemaphoreTake()`函数获取信号量,并使用`xSemaphoreGive()`函数释放信号量。 例如,以下是一个使用二进制信号量的示例: ```c // 创建一个二进制信号量 SemaphoreHandle_t xSemaphore = xSemaphoreCreateBinary(); // 任务1 void task1(void* parameter) { while (1) { // 获取信号量 if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) { // 访问共享资源 // ... // 释放信号量 xSemaphoreGive(xSemaphore); } } } // 任务2 void task2(void* parameter) { while (1) { // 获取信号量 if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) { // 访问共享资源 // ... // 释放信号量 xSemaphoreGive(xSemaphore); } } } ``` 在上面的示例中,任务1和任务2通过获取和释放同一个二进制信号量来对共享资源进行保护。只有当一个任务成功获取到信号量时,才能访问共享资源,否则会被阻塞等待。 需要注意的是,在使用计数信号量时,可以使用`xSemaphoreTake()`函数的第二个参数来设置等待时间,以避免永久阻塞。 这只是一个简单的示例,FreeRTOS中的信号量还有其他用法和特性,例如递归信号量和优先级反转处理。您可以参考FreeRTOS的官方文档和示例代码来了解更多信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值