进程间通信

本文介绍了进程间通信的几种方式,包括管道(匿名管道和命名管道)、消息队列、共享存储(shm和mmap)和信号量。详细说明了匿名管道的特点、命名管道的适用范围,还给出了消息队列、共享存储的相关函数,以及信号量的作用是保证多进程资源竞争时的同步。

目录

一、管道

        1、匿名管道

        2、命名管道

二、消息队列

三、共享存储

四、信号量


一、管道

        1、匿名管道

                        有亲缘关系的进程实现进程间通信

 #include <unistd.h>

 int pipe(int pipefd[2]);

        pipefd[0]--->read
        pipefd[1]--->write

        特点:
                1. 半双工通讯
                2. 必须凑齐读端和写端
                3. 所有写端关闭,read就会返回0
                4. 所有读端关闭,write产生SIGPIPE异常,如果此信号忽略,则write返回-1并errno值设置为EPIPE
                5. 有容量,写满管道,write会阻塞
                6. 读空管道,read会阻塞

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <stdlib.h>

#define BUFSIZE	32

static int cpFl(int rfd, int wfd);
int main(int argc, char *argv[])
{
	int fd;
	int pfd[2] = {};
	pid_t pid;

	if (argc < 2)
		return 1;

	if (-1 == pipe(pfd)) {
		perror("pipe()");
		exit(1);
	}
	pid = fork();
	if (-1 == pid) {
		perror("fork()");
		exit(1);
	}
	if (0 == pid) {
		close(pfd[1]);
		cpFl(pfd[0], 1);
		close(pfd[0]);
		exit(0);
	}

	close(pfd[0]);
	fd = open(argv[1], O_RDONLY);
	if (-1 == fd) {
		perror("open()");
		close(pfd[1]);
		exit(1);
	}
	cpFl(fd, pfd[1]);
	close(pfd[1]);
	close(fd);

	wait(NULL);

	exit(0);
}

static int cpFl(int rfd, int wfd)
{
	char buf[BUFSIZE] = {};
	int cnt;
	
	while (1) {
		cnt = read(rfd, buf, BUFSIZE);
		if (-1 == cnt) {
			perror("read()");
			return -1;
		}
		if (0 == cnt)
			break;
		write(wfd, buf, cnt);
	}
	return 0;
}


        2、命名管道

        不仅局限与有亲缘关系的进程,所有的进程都能够操作此管道

#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);

可参考mkfifo函数

二、消息队列

        就是一个能应用于进程间数据交换的队列,符合队列特点
                `int msgget(key_t key, int flags)`
                `int msgrcv(int msgid, void *buf, int size, int type, int flag)`
                `int msgsnd(int msgid, const void *buf, int size, int flag)`
                `int msgctl(int msgid, int cmd, struct msgid_ds *ds)`

三、共享存储

1. shm(是否有亲缘关系都可)
    1. 创建
    `int shmget(key_t key, int size, int flag)`
    2. 映射
    `void *shmat(int shmid, const void *addr, int flag)`
    `int shmdt(void *addr)`
    3. 获得状态/销毁
    `int shmctl(int shmid, int cmd, struct shmid_ds *ds)`
2. mmap(仅限于有亲缘关系的进程)
    `void *mmap(void *addr, int size, int prot, int flag, int fd, offet_t off)`

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>

int main(void)
{
	int shmid;
	pid_t pid;
	char *ptr;

	// 创建共享内存
	shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT | IPC_EXCL | 0600);
	if (-1 == shmid) {
		perror("shmget()");
		exit(1);
	}

	// 创建子进程
	pid = fork();
	if (-1 == pid) {
		perror("fork()");
		goto ERROR;
	}
	// 各自映射
	if (0 == pid) {
		ptr = (char *)shmat(shmid, NULL, 0);
		if ((void *)-1 == ptr) {
			perror("shmat()");
			exit(1);
		}
		strcpy(ptr, "good morning");
		shmdt(ptr);
		exit(0);
	}

	wait(NULL);
	ptr = shmat(shmid, NULL, 0);
	// if error
	sleep(10);
	puts(ptr);
	shmdt(ptr);

	// 销毁
	shmctl(shmid, IPC_RMID, NULL);
	return 0;
ERROR:
	shmctl(shmid, IPC_RMID, NULL);
	exit(1);
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>

// 有亲缘关系的进程得到一端共享内存

int main(void)
{
	pid_t pid;
	void *ptr = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

	pid = fork();
	if (-1 == pid) {
		perror("fork()");
		exit(1);
	}
	if (0 == pid) {
		memcpy(ptr, "good afternoon", 14);
		exit(0);
	}
	wait(NULL);
	puts(ptr);
	munmap(ptr, 1024);

	return 0;
}

四、信号量

                保证多进程资源竞争的时候同步

### 如何在 Spring Boot 中使用 `@Scheduled` 注解实现定时任务 #### 配置主类或配置类 为了启用定时任务功能,在 Spring Boot 的主应用程序类或者某个配置类上需要添加 `@EnableScheduling` 注解。这一步是必不可少的,因为该注解会激活 Spring 容器内的调度机制[^2]。 ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableScheduling // 启用定时任务功能 public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } } ``` --- #### 创建定时任务方法 创建一个普通的组件类(通过 `@Component` 或其他类似的注解标记),并在其中定义带有 `@Scheduled` 注解的方法。此注解用于指定任务执行的时间间隔或其他触发条件[^3]。 以下是几种常见的定时任务设置方式: 1. **基于固定时间间隔的任务** 可以使用 `fixedRate` 属性来设定每次任务之间的最小间隔时间(单位为毫秒)。 ```java import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class ScheduledTasks { @Scheduled(fixedRate = 5000) // 每隔 5 秒运行一次 public void fixedRateTask() { System.out.println("Fixed Rate Task executed at: " + System.currentTimeMillis()); } } ``` 2. **基于延迟时间间隔的任务** 如果希望当前任务完成后等待一段时间再启动下一个任务,则可以使用 `fixedDelay` 属性。 ```java @Scheduled(fixedDelay = 10000) // 当前任务结束后等待 10 秒再运行下一次 public void fixedDelayTask() { System.out.println("Fixed Delay Task executed at: " + System.currentTimeMillis()); } ``` 3. **基于 Cron 表达式的复杂任务计划** 对于更复杂的场景,比如每天凌晨两点执行某项操作,可以通过 `cron` 属性提供自定义表达式。 ```java @Scheduled(cron = "0 0/5 * * * ?") // 每五分钟运行一次 public void cronTask() { System.out.println("Cron Task executed at: " + System.currentTimeMillis()); } @Scheduled(cron = "0 0 2 * * ?") // 每天凌晨两点运行一次 public void dailyCronTask() { System.out.println("Daily Cron Task executed at: " + System.currentTimeMillis()); } ``` --- #### 注意事项 - 默认情况下,`@Scheduled` 基于单线程池工作。如果多个任务可能重叠或耗时较长,建议调整线程池大小以提高并发能力。 - 若要修改默认行为,可以在配置文件中加入如下属性: ```properties spring.task.scheduling.pool.size=5 # 设置线程池大小为 5 ``` - 时间计算均基于 JVM 所在服务器的本地时区。因此需注意部署环境与时区的一致性问题。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值