在操作系统中,任务通信是确保多个进程或线程之间能够高效、可靠地交换信息和数据的关键。以下是四种常见的任务通信技巧,它们能够帮助提升系统的运行效率。
1. 管道(Pipe)
管道是一种用于在两个进程之间传递数据的线性数据流。它允许一个进程将数据写入管道,另一个进程从管道中读取数据。管道分为无名管道和命名管道。
无名管道
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
int pipefd[2];
pid_t pid;
if (pipe(pipefd) == -1) {
perror("pipe");
return 1;
}
pid = fork();
if (pid == 0) {
// 子进程,写入数据
close(pipefd[0]); // 关闭读端
write(pipefd[1], "Hello, world!\n", 14);
close(pipefd[1]); // 关闭写端
} else if (pid > 0) {
// 父进程,读取数据
close(pipefd[1]); // 关闭写端
char buffer[20];
read(pipefd[0], buffer, 19);
printf("Received: %s\n", buffer);
close(pipefd[0]); // 关闭读端
} else {
perror("fork");
return 1;
}
return 0;
}
命名管道(FIFO)
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
int main() {
int fifo_fd;
const char *fifo_path = "/tmp/my_fifo";
// 创建命名管道
if (mkfifo(fifo_path, 0666) == -1) {
perror("mkfifo");
return 1;
}
pid_t pid = fork();
if (pid == 0) {
// 子进程,写入数据
fifo_fd = open(fifo_path, O_WRONLY);
write(fifo_fd, "Hello, world!\n", 14);
close(fifo_fd);
} else if (pid > 0) {
// 父进程,读取数据
fifo_fd = open(fifo_path, O_RDONLY);
char buffer[20];
read(fifo_fd, buffer, 19);
printf("Received: %s\n", buffer);
close(fifo_fd);
} else {
perror("fork");
return 1;
}
// 删除命名管道
unlink(fifo_path);
return 0;
}
2. 套接字(Socket)
套接字是一种通信协议,它允许不同主机上的进程进行网络通信。套接字分为流式套接字和数据报套接字。
流式套接字
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
int sockfd;
struct sockaddr_in servaddr;
// 创建套接字
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(8080);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
// 绑定套接字
if (bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
// 监听套接字
if (listen(sockfd, 10) == -1) {
perror("listen");
exit(EXIT_FAILURE);
}
// 接受连接
int newsockfd;
socklen_t len = sizeof(servaddr);
if ((newsockfd = accept(sockfd, (struct sockaddr *)&servaddr, &len)) == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
// 读取数据
char buffer[1024];
int n = read(newsockfd, buffer, sizeof(buffer));
printf("Received: %s\n", buffer);
// 关闭套接字
close(newsockfd);
close(sockfd);
return 0;
}
数据报套接字
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
int sockfd;
struct sockaddr_in servaddr;
// 创建套接字
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(8080);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
// 绑定套接字
if (bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
// 发送数据
char buffer[] = "Hello, UDP!";
sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
// 接收数据
char buffer2[1024];
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
recvfrom(sockfd, buffer2, sizeof(buffer2), 0, (struct sockaddr *)&client_addr, &client_len);
printf("Received: %s\n", buffer2);
// 关闭套接字
close(sockfd);
return 0;
}
3. 信号量(Semaphore)
信号量是一种同步机制,用于控制对共享资源的访问。它分为二进制信号量和计数信号量。
二进制信号量
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
int main() {
key_t key = ftok("semfile", 65);
int semid = semget(key, 1, 0666);
struct sembuf sop;
// 初始化信号量
union semun init_value;
init_value.val = 1;
semctl(semid, 0, SETVAL, init_value);
// P操作
sop.sem_num = 0;
sop.sem_op = -1; // P操作
sop.sem_flg = 0;
semop(semid, &sop, 1);
printf("Semaphore value: %d\n", semctl(semid, 0, GETVAL, init_value).val);
// V操作
sop.sem_op = 1; // V操作
semop(semid, &sop, 1);
printf("Semaphore value: %d\n", semctl(semid, 0, GETVAL, init_value).val);
// 删除信号量集
semctl(semid, 0, IPC_RMID, init_value);
return 0;
}
计数信号量
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
int main() {
key_t key = ftok("semfile", 65);
int semid = semget(key, 1, 0666);
struct sembuf sop;
// 初始化信号量
union semun init_value;
init_value.val = 1;
semctl(semid, 0, SETVAL, init_value);
// P操作
sop.sem_num = 0;
sop.sem_op = -1; // P操作
sop.sem_flg = 0;
semop(semid, &sop, 1);
printf("Semaphore value: %d\n", semctl(semid, 0, GETVAL, init_value).val);
// V操作
sop.sem_op = 1; // V操作
semop(semid, &sop, 1);
printf("Semaphore value: %d\n", semctl(semid, 0, GETVAL, init_value).val);
// 删除信号量集
semctl(semid, 0, IPC_RMID, init_value);
return 0;
}
4. 条件变量(Condition Variable)
条件变量是一种线程同步机制,用于在线程之间同步。它通常与互斥锁一起使用。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
void *producer(void *arg) {
pthread_mutex_lock(&mutex);
// ... 生产数据 ...
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
return NULL;
}
void *consumer(void *arg) {
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
// ... 消费数据 ...
pthread_mutex_unlock(&mutex);
return NULL;
}
int main() {
pthread_t prod, cons;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_create(&prod, NULL, producer, NULL);
pthread_create(&cons, NULL, consumer, NULL);
pthread_join(prod, NULL);
pthread_join(cons, NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
以上四种任务通信技巧可以帮助你提升操作系统的运行效率。在实际开发中,根据不同的场景和需求选择合适的通信方式非常重要。
