【Linux系统编程】System V信号量_什么函数用于对信号量或信号量集合进行操作-程序员宅基地

技术标签: semget  Linux环境高级编程  semop  System V信号量  信号量  semctl  

00. 目录

01. 信号量概述

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

编程时可根据操作信号量值的结果判断是否对公共资源具有访问的权限,当信号量值大于 0 时,则可以访问,否则将阻塞。PV 原语是对信号量的操作,一次 P 操作使信号量减1,一次 V 操作使信号量加1。

在实际应用中两个进程间通信可能会使用多个信号量,因此 System V 的信号量以集合的概念来管理,具体操作和 Posix 信号量大同小异 。

信号量集合数据结构:struct semid_ds,此数据结构中定义了整个信号量集的基本属性。

/* Obsolete, used only for backwards compatibility and libc5 compiles */
struct semid_ds
{
    
	struct ipc_perm	sem_perm;		/* permissions .. see ipc.h */
	__kernel_time_t	sem_otime;		/* last semop time */
	__kernel_time_t	sem_ctime;		/* last change time */
	struct sem	*sem_base;		/* ptr to first semaphore in array */
	struct sem_queue *sem_pending;		/* pending operations to be processed */
	struct sem_queue **sem_pending_last;	/* last pending operation */
	struct sem_undo	*undo;			/* undo requests on this array */
	unsigned short	sem_nsems;		/* no. of semaphores in array */
};

信号量数据结构:struct sem,此数据结构中定义了信号量的基本属性。

/* One semaphore structure for each semaphore in the system. */
struct sem
{
    
	int	semval;		/* current value *信号量的值*/
	int	sempid;		/* pid of last operation *最后一个操作信号量的进程号*/
	struct list_head sem_pending; /* pending single-sop operations */
};

02. 信号量操作命令

查看信号量数组

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ipcs -s

--------- 信号量数组 -----------
键        semid      拥有者  权限     nsems     

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ 

删除信号量数组

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ipcrm -s semid 

03. 信号量操作函数

3.1 创建信号量数组

int semget(key_t key, int nsems, int semflg);
功能:
	创建或打开一个信号量集合,该集合中可以包含多个信号量。
参数:
	key:进程间通信键值,通过调用 ftok() 函数得到的键值
	nsems:创建的信号量的个数。如果只是访问而不创建则可以指定该参数为 0,一旦创建了该信号量,
    就不能更改其信号量个数,只要不删除该信号量,重新调用该函数创建该键值的信号量,
    该函数只是返回以前创建的值,不会重新创建。

	semflg:标识函数的行为及信号量的权限,其取值如下:
		IPC_CREAT:创建信号量。
		IPC_EXCL:检测信号量是否存在。
		位或权限位:信号量位或权限位后可以设置信号量的访问权限,格式和 open 函数的 mode_ t
    	一样(open() 的使用请点此链接),但可执行权限未使用。
返回值:
	成功:信号量集标识符
	失败:返回 -1

3.2 信号量控制函数

int semctl(int semid, int semnum, int cmd, ...);
功能:
	对信号量集合以及集合中的信号量进行操作。
参数:
	semid:信号量集标识符。
	semnum:集合中信号量的序号,指定对哪个信号量操作, 只对几个特殊的 cmd 操作有意义。
	cmd:信号量控制类型。semctl() 函数可能有3个参数,也可能有4个参数,参数的个数由 cmd 决定。
    当有4个参数时,第4个参数为联合体:
	
    union semun{
    
	int			val;	/*信号量的值*/
	struct semid_ds *buf;	/*信号量集合信息*/
	unsigned short  *array;/*信号量值的数组*/
	struct seminfo  *__buf;/*信号量限制信息*/
};
	cmd 的取值如下:
        
	GETVAL:获取信号量的值。此时函数有3个参数。semctl() 函数的返回值即为信号量的值。
	SETVAL:设置信号量的值。此时函数有4个参数。第4个参数为联合体中的val,其值为信号量的值。 
	IPC_STAT:获取信号量集合的信息。此时函数有4个参数。第4个参数为联合体中的__buf。
	IPC_SET:设置信号量集合的信息。此时函数有4个参数。第4个参数为联合体中的__buf。
	IPC_RMID:删除信号量集。此时函数有3个参数,2个参数semnum不起作用。
	GETALL:获取所有信号量的值。此时函数有4个参数,第2个参数semnum不起作用。
            第4个参数为联合体中的array,其值为用来存放所有信号量值的数组的首地址。
	SETALL:设置所有信号量的值 。参数说明同上。
	IPC_INFO:获取信号量集合的限制信息。此时函数有4个参数,第2个参数semnum不起作用。
    		 第4个参数为联合体中的__buf。
	GETPID:获取信号的进程号,即最后操作信号量的进程。此时函数有3个参数。
		    semctl() 函数的返回值即为信号的进程号。
	GETNCNT:获取等待信号的值递增的进程数。此时函数有3个参数。semctl() 函数的返回值即为进程数。
	GETZCNT:获取等待信号的值递减的进程数。此时函数有3个参数。semctl() 函数的返回值即为进程数。
返回值:
	成功:0
	失败:-1

3.3 信号量操作函数

int semop(int semid, struct sembuf *sops, unsigned nsops);
功能:
	操作信号量,主要进行信号量加减操作。
参数:
	semid:信号量集标识符。
	sops:操作信号量的结构体(struct sembuf)数组的首地址( 结构体定义在 sys/sem.h ),
    此结构体中的数据表明了对信号量进行的操作。
    struct sembuf{
    
        unsigned short  sem_num;	/*信号量的序号*/
        short       sem_op;		/*信号量的操作值*/
        short       sem_flg;	/*信号量的操作标识*/
    };
结构体成员使用说明如下:

sem_num:信号量集中信号量的序号
sem_op 取值如下:
sem_op > 0:信号量的值在原来的基础上加上此值。
sem_op < 0:如果信号量的值小于 semop 的绝对值,则挂起操作进程。
    	    如果信号量的值大于等于 semop 的绝对值,
            则信号量的值在原来的基础上减去 semop 的绝对值。
sem_op = 0:对信号量的值进行是否为 0 测试。若为 0 则函数立即返回,若不为 0 则阻塞调用进程。
sem_flag 取值如下: 
	IPC_NOWAIT:在对信号量的操作不能执行的情况下使函数立即返回。
	SEM_UNDO:当进程退出后,该进程对信号量进行的操作将被撤销。
nsops:操作信号量的结构体数组中元素的个数。
    
返回值:
	成功:0
	失败:-1

04. 程序示例

4.1 创建和删除信号量数组

#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <stdio.h>
 
int main(int argc, char *argv[])
{
    
	key_t key;
 
	//创建key值
	key = ftok(".", 'a');
	if(key == -1)
	{
    
		perror("ftok");
	}
	
	//查看信号量
	system("ipcs -s");
	
	int semid;
	
	//1: 创建的信号量的个数
	semid = semget(key, 1, IPC_CREAT|0666); //创建信号量
	if(semid == -1)
	{
    
		perror("semget");
	}
	
	system("ipcs -s"); //查看信号量
	
	//删去信号量
	// 0: 代表对第0个信号量进行操作
	// IPC_RMID:删除信号量集
	semctl(semid, 0, IPC_RMID);
	
	system("ipcs -s"); //查看信号量
	
	return 0;
}

执行结果:

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ gcc 1.c 
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out  

--------- 信号量数组 -----------
键        semid      拥有者  权限     nsems     


--------- 信号量数组 -----------
键        semid      拥有者  权限     nsems     
0x61320009 0          deng       666        1         


--------- 信号量数组 -----------
键        semid      拥有者  权限     nsems     

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ 

4.2 获取信号量数组相关信息

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <stdio.h>
 
/*解决编译出错的问题*/
#define IPC_INFO 3
 
int main(int argc, char *argv[])
{
    
	key_t key;
 
	//创建key值
	key = ftok(".", 'a');
	if(key == -1)
	{
    
		perror("ftok");
	}
	
	system("ipcs -s"); //查看信号量
	
	int semid;
	//1: 创建的信号量的个数
	semid = semget(key, 1, IPC_CREAT|0666);//创建信号量
	if(semid == -1)
	{
    
		perror("semget");
	}
	
	system("ipcs -s"); //查看信号量
	
	struct seminfo buf;
	/*
	//struct seminfo相关成员
	struct seminfo {
		int semmap;
		int semmni;
		int semmns;
		int semmnu;
		int semmsl;
		int semopm;
		int semume;
		int semusz;
		int semvmx;
		int semaem;
	};
	
	*/
	
	//IPC_INFO:获取信号量集合的限制信息。
	//此时函数有4个参数,第2个参数semnum不起作用。
	semctl(semid, 0, IPC_INFO, &buf);
	
	printf("buf.semmni = %d\n", buf.semmni);
	printf("buf.semmns = %d\n", buf.semmns);
	printf("buf.semmnu = %d\n", buf.semmnu);
	printf("buf.semmsl = %d\n", buf.semmsl);
	printf("buf.semopm = %d\n", buf.semopm);
	printf("buf.semume = %d\n", buf.semume);
	printf("buf.semusz = %d\n", buf.semusz);
	printf("buf.semvmx = %d\n", buf.semvmx);
	printf("buf.semaem = %d\n", buf.semaem);
 
	//删去信号量
	// 0: 代表对第0个信号量进行操作
	// IPC_RMID:删除信号量集
	semctl(semid, 0, IPC_RMID);
	
	system("ipcs -s"); //查看信号量
	
	return 0;
}

测试结果:

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ gcc 1.c 
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out  

--------- 信号量数组 -----------
键        semid      拥有者  权限     nsems     


--------- 信号量数组 -----------
键        semid      拥有者  权限     nsems     
0x61320009 32768      deng       666        1         

buf.semmni = 32000
buf.semmns = 1024000000
buf.semmnu = 1024000000
buf.semmsl = 32000
buf.semopm = 500
buf.semume = 500
buf.semusz = 20
buf.semvmx = 32767
buf.semaem = 32767

--------- 信号量数组 -----------
键        semid      拥有者  权限     nsems     

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ 

4.3 获取和设置信号量数组的值

#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <stdio.h>
 
int main(int argc, char *argv[])
{
    
	key_t key;
 
	//创建key值
	key = ftok(".", 'a');
	if(key == -1)
	{
    
		perror("ftok");
	}
	
	//查看信号量
	system("ipcs -s");
	
	int semid;
	
	//1: 创建的信号量的个数
	semid = semget(key, 1, IPC_CREAT|0666); //创建信号量
	if(semid == -1)
	{
    
		perror("semget");
	}
	
	system("ipcs -s"); //查看信号量
	
	int ret;
	
	/*
	//SETVAL: 设置信号量的值。此时函数有4个参数。第4个参数为联合体中的val,其值为信号量的值。 
	union semun{
		int			val;		//信号量的值
		struct semid_ds *buf;	//信号量集合信息
		unsigned short  *array;	//信号量值的数组
		struct seminfo  *__buf;	//信号量限制信息
	};
	*/
	ret = semctl(semid, 0, SETVAL, 20);
	if(ret == -1)
	{
    
		perror("semctl");
	}
	
	//GETVAL:获取信号量的值。函数返回值即为信号量的值。
	ret = semctl(semid, 0, GETVAL);
	if(ret == -1)
	{
    
		perror("semctl");
	}
	printf("ret = %d\n", ret);
 
	// 0: 代表对第0个信号量进行操作
	// IPC_RMID:删除信号量集
	semctl(semid, 0, IPC_RMID);
	
	system("ipcs -s");
	
	return 0;
}

测试结果:

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ gcc 1.c 
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out  

--------- 信号量数组 -----------
键        semid      拥有者  权限     nsems     


--------- 信号量数组 -----------
键        semid      拥有者  权限     nsems     
0x61320009 65536      deng       666        1         

ret = 20

--------- 信号量数组 -----------
键        semid      拥有者  权限     nsems     

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ 

4.4 信号量数组

#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
 
int main(int argc, char *argv[])
{
    
	key_t key;
 
	//创建key值
	key = ftok(".", 'a');
	if(key == -1)
	{
    
		perror("ftok");
	}
	
	//查看信号量
	system("ipcs -s");
	
	int semid;
	
	//2: 创建的信号量的个数
	semid = semget(key, 2, IPC_CREAT|0666); //创建信号量
	if(semid == -1)
	{
    
		perror("semget");
	}
	
	system("ipcs -s"); //查看信号量
	
	int ret;
 
	unsigned short sem_arry[2] = {
    30,20};
	
	/*
	//SETALL: 设置所有信号量的值。此时函数有4个参数,第2个参数semnum不起作用。第4个参数为联合体中的array,其值为用来存放所有信号量值的数组的首地址。
	union semun{
		int			val;		//信号量的值
		struct semid_ds *buf;	//信号量集合信息
		unsigned short  *array;	//信号量值的数组
		struct seminfo  *__buf;	//信号量限制信息
	};
	*/
	ret = semctl(semid, 0, SETALL, sem_arry);
	if(ret == -1)
	{
    
		perror("semctl");
	}
	
	
	bzero(sem_arry, sizeof(sem_arry));
	//GETALL:获取所有信号量的值。此时函数有4个参数,
	//第2个参数semnum不起作用。第4个参数为联合体中的array,
	//其值为用来存放所有信号量值的数组的首地址。
	ret = semctl(semid, 0, GETALL, sem_arry);
	if(ret == -1)
	{
    
		perror("semctl");
	}
	printf("sem_arry[0] = %d\n", sem_arry[0]);
	printf("sem_arry[1] = %d\n", sem_arry[1]);
 
	// IPC_RMID:删除信号量集
	semctl(semid, 0, IPC_RMID);
	system("ipcs -s");
	
	return 0;
}

测试结果:

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ gcc 1.c 
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out  

--------- 信号量数组 -----------
键        semid      拥有者  权限     nsems     


--------- 信号量数组 -----------
键        semid      拥有者  权限     nsems     
0x61320009 98304      deng       666        2         

sem_arry[0] = 30
sem_arry[1] = 20

--------- 信号量数组 -----------
键        semid      拥有者  权限     nsems     

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ 

4.5 综合实例

//此范例使用信号量来同步共享内存的操作
#include <stdio.h> 
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/sem.h> 
#include <sys/shm.h>
#include <unistd.h>
#include <sys/wait.h>
 
#define SHM_KEY 0x33 
#define SEM_KEY 0x44 
 
union semun 
{
     
	int val; 
	struct semid_ds *buf; 
	unsigned short *array; 
}; 
 
int P(int semid) 
{
     
	struct sembuf sb;
	/*
	//操作信号量的结构体
	struct sembuf{
		unsigned short  sem_num;//信号量的序号
		short       sem_op;		//信号量的操作值
		short       sem_flg;	//信号量的操作标识
	};	
	*/
	sb.sem_num = 0; 
	sb.sem_op = -1;
	//SEM_UNDO:当进程退出后,该进程对信号量进行的操作将被撤销。
	sb.sem_flg = SEM_UNDO; 
 
	//操作1个信号量
	if(semop(semid, &sb, 1) == -1){
     
		perror("semop"); 
		return -1; 
	} 
 
	return 0; 
} 
 
int V(int semid) 
{
     
	struct sembuf sb;
	/*
	//操作信号量的结构体
	struct sembuf{
		unsigned short  sem_num;//信号量的序号
		short       sem_op;		//信号量的操作值
		short       sem_flg;	//信号量的操作标识
	};	
	*/
	
	sb.sem_num = 0; 
	sb.sem_op = 1;
	//SEM_UNDO:当进程退出后,该进程对信号量进行的操作将被撤销。
	sb.sem_flg = SEM_UNDO; 
 
	//操作1个信号量
	if(semop(semid, &sb, 1) == -1){
     
		perror("semop"); 
		return -1; 
	} 
	
	return 0; 
} 
 
int main(int argc, char **argv) 
{
    
	pid_t pid; 
	int i, shmid, semid; 
	int *ptr = NULL; 
	union semun semopts; 
	/*
	union semun{
		int			val;		//信号量的值
		struct semid_ds *buf;	//信号量集合信息
		unsigned short  *array;	//信号量值的数组
		struct seminfo  *__buf;	//信号量限制信息
	};
	*/
 
	//创建一块共享内存, 存一个int变量
	if ((shmid = shmget(SHM_KEY, sizeof(int), IPC_CREAT | 0600)) == -1) {
     
		perror("msgget"); 
		return -1;
	} 
 
	//将共享内存映射到进程, fork后子进程可以继承映射
	ptr = (int *)shmat(shmid, NULL, 0);
	if (ptr == (int *)-1) {
     
		perror("shmat");
		return -1;
	}
	
	*ptr = 0; //赋值为0
 
	// 创建一个信号量用来同步共享内存的操作 
	if ((semid = semget(SEM_KEY, 1, IPC_CREAT | 0600)) == -1) {
     
		perror("semget"); 
		return -1;
	} 
 
	//初始化信号量  
	semopts.val = 1; 
	if (semctl(semid, 0, SETVAL, semopts) < 0) {
     
		perror("semctl"); 
		return -1;
	} 
 
	if ((pid = fork()) < 0) {
     //创建进程
		perror("fork");
		_exit(0);
	}else if (pid == 0){
     // Child
		// 子进程对共享内存加1 
		for (i = 0; i < 100000; i++) {
     
			P(semid); 
			(*ptr)++; 
			V(semid); 
			printf("child: %d\n", *ptr); 
		} 
		
	} else {
     //Parent
		// 父进程对共享内存减1 
		for (i = 0; i < 100000; i++) {
     
			P(semid); 
			(*ptr)--; 
			V(semid); 
			printf("parent: %d\n", *ptr); 
		} 
		
		//如果子进程结束,回收其资源
		wait(NULL);
		
		//如果同步成功, 共享内存的值为0 
		printf("finally: %d\n", *ptr); 
	} 
 
	return 0; 
} 

执行结果:

child: -30
child: -29
child: -28
child: -27
child: -26
child: -25
child: -24
child: -23
child: -22
child: -21
child: -20
child: -19
child: -18
child: -17
child: -16
child: -15
child: -14
child: -13
child: -12
child: -11
child: -10
child: -9
child: -8
child: -7
child: -6
child: -5
child: -4
child: -3
child: -2
child: -1
child: 0
finally: 0

05. 附录

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/dengjin20104042056/article/details/102970461

智能推荐

前端开发之vue-grid-layout的使用和实例-程序员宅基地

文章浏览阅读1.1w次,点赞7次,收藏34次。vue-grid-layout的使用、实例、遇到的问题和解决方案_vue-grid-layout

Power Apps-上传附件控件_powerapps点击按钮上传附件-程序员宅基地

文章浏览阅读218次。然后连接一个数据源,就会在下面自动产生一个添加附件的组件。把这个控件复制粘贴到页面里,就可以单独使用来上传了。插入一个“编辑”窗体。_powerapps点击按钮上传附件

C++ 面向对象(Object-Oriented)的特征 & 构造函数& 析构函数_"object(cnofd[\"ofdrender\"])十条"-程序员宅基地

文章浏览阅读264次。(1) Abstraction (抽象)(2) Polymorphism (多态)(3) Inheritance (继承)(4) Encapsulation (封装)_"object(cnofd[\"ofdrender\"])十条"

修改node_modules源码,并保存,使用patch-package打补丁,git提交代码后,所有人可以用到修改后的_修改 node_modules-程序员宅基地

文章浏览阅读133次。删除node_modules,重新npm install看是否成功。在 package.json 文件中的 scripts 中加入。修改你的第三方库的bug等。然后目录会多出一个目录文件。_修改 node_modules

【】kali--password:su的 Authentication failure问题,&sudo passwd root输入密码时Sorry, try again._password: su: authentication failure-程序员宅基地

文章浏览阅读883次。【代码】【】kali--password:su的 Authentication failure问题,&sudo passwd root输入密码时Sorry, try again._password: su: authentication failure

整理5个优秀的微信小程序开源项目_微信小程序开源模板-程序员宅基地

文章浏览阅读1w次,点赞13次,收藏97次。整理5个优秀的微信小程序开源项目。收集了微信小程序开发过程中会使用到的资料、问题以及第三方组件库。_微信小程序开源模板

随便推点

Centos7最简搭建NFS服务器_centos7 搭建nfs server-程序员宅基地

文章浏览阅读128次。Centos7最简搭建NFS服务器_centos7 搭建nfs server

Springboot整合Mybatis-Plus使用总结(mybatis 坑补充)_mybaitis-plus ruledataobjectattributemapper' and '-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏3次。前言mybatis在持久层框架中还是比较火的,一般项目都是基于ssm。虽然mybatis可以直接在xml中通过SQL语句操作数据库,很是灵活。但正其操作都要通过SQL语句进行,就必须写大量的xml文件,很是麻烦。mybatis-plus就很好的解决了这个问题。..._mybaitis-plus ruledataobjectattributemapper' and 'com.picc.rule.management.d

EECE 1080C / Programming for ECESummer 2022 Laboratory 4: Global Functions Practice_eece1080c-程序员宅基地

文章浏览阅读325次。EECE 1080C / Programming for ECESummer 2022Laboratory 4: Global Functions PracticePlagiarism will not be tolerated:Topics covered:function creation and call statements (emphasis on global functions)Objective:To practice program development b_eece1080c

洛谷p4777 【模板】扩展中国剩余定理-程序员宅基地

文章浏览阅读53次。被同机房早就1年前就学过的东西我现在才学,wtcl。设要求的数为\(x\)。设当前处理到第\(k\)个同余式,设\(M = LCM ^ {k - 1} _ {i - 1}\) ,前\(k - 1\)个的通解就是\(x + i * M\)。那么其实第\(k\)个来说,其实就是求一个\(y\)使得\(x + y * M ≡ a_k(mod b_k)\)转化一下就是\(y * M ...

android 退出应用没有走ondestory方法,[Android基础论]为何Activity退出之后,系统没有调用onDestroy方法?...-程序员宅基地

文章浏览阅读1.3k次。首先,问题是如何出现的?晚上复查代码,发现一个activity没有调用自己的ondestroy方法我表示非常的费解,于是我检查了下代码。发现再finish代码之后接了如下代码finish();System.exit(0);//这就是罪魁祸首为什么这样写会出现问题System.exit(0);////看一下函数的原型public static void exit (int code)//Added ..._android 手动杀死app,activity不执行ondestroy

SylixOS快问快答_select函数 导致堆栈溢出 sylixos-程序员宅基地

文章浏览阅读894次。Q: SylixOS 版权是什么形式, 是否分为<开发版税>和<运行时版税>.A: SylixOS 是开源并免费的操作系统, 支持 BSD/GPL 协议(GPL 版本暂未确定). 没有任何的运行时版税. 您可以用她来做任何 您喜欢做的项目. 也可以修改 SylixOS 的源代码, 不需要支付任何费用. 当然笔者希望您可以将使用 SylixOS 开发的项目 (不需要开源)或对 SylixOS 源码的修改及时告知笔者.需要指出: SylixOS 本身仅是笔者用来提升自己水平而开发的_select函数 导致堆栈溢出 sylixos

推荐文章

热门文章

相关标签