|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
引言
Linux作为开源操作系统的代表,在服务器、嵌入式系统和开发环境中占据着重要地位。掌握Linux高级编程技能对于系统开发人员来说至关重要。本文将深入浅出地介绍Linux高级编程的核心技能,包括系统调用、内存管理、进程控制、文件操作、网络编程和多线程开发,帮助读者快速提升Linux系统开发能力。
系统调用
什么是系统调用
系统调用是用户空间程序与内核空间交互的接口,是操作系统提供给应用程序的服务入口。通过系统调用,应用程序可以请求操作系统执行特权操作,如硬件访问、进程创建、文件操作等。
为什么需要系统调用
系统调用存在的必要性主要体现在以下几个方面:
1. 安全性:防止用户程序直接访问硬件资源,确保系统安全
2. 稳定性:提供统一的接口,避免应用程序直接操作内核
3. 抽象性:简化复杂的硬件操作,提供易于使用的API
常用系统调用及示例
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- int main() {
- int fd;
- char buffer[1024];
- ssize_t bytes_read;
-
- // 使用open系统调用打开文件
- fd = open("example.txt", O_RDONLY);
- if (fd == -1) {
- perror("open");
- exit(EXIT_FAILURE);
- }
-
- // 使用read系统调用读取文件内容
- bytes_read = read(fd, buffer, sizeof(buffer) - 1);
- if (bytes_read == -1) {
- perror("read");
- close(fd);
- exit(EXIT_FAILURE);
- }
-
- buffer[bytes_read] = '\0'; // 确保字符串以null结尾
- printf("读取的内容: %s\n", buffer);
-
- // 使用close系统调用关闭文件
- if (close(fd) == -1) {
- perror("close");
- exit(EXIT_FAILURE);
- }
-
- return 0;
- }
复制代码- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/wait.h>
- int main() {
- pid_t pid;
- int status;
-
- // 使用fork系统调用创建子进程
- pid = fork();
-
- if (pid == -1) {
- perror("fork");
- exit(EXIT_FAILURE);
- } else if (pid == 0) {
- // 子进程代码
- printf("子进程: PID = %d, 父进程PID = %d\n", getpid(), getppid());
- // 使用execlp系统调用执行新程序
- execlp("ls", "ls", "-l", NULL);
- // 如果execlp执行成功,下面的代码不会执行
- perror("execlp");
- exit(EXIT_FAILURE);
- } else {
- // 父进程代码
- printf("父进程: PID = %d, 子进程PID = %d\n", getpid(), pid);
- // 使用waitpid系统调用等待子进程结束
- waitpid(pid, &status, 0);
- printf("子进程结束,状态: %d\n", status);
- }
-
- return 0;
- }
复制代码
内存管理
Linux内存管理概述
Linux内存管理负责分配和回收内存资源,包括物理内存和虚拟内存。内存管理的核心功能包括:
1. 内存分配:为进程分配所需的内存空间
2. 内存映射:将文件或设备映射到进程地址空间
3. 内存保护:控制内存访问权限
4. 内存共享:允许多个进程共享内存区域
内存分配函数
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- int main() {
- char *buffer;
-
- // 使用malloc分配内存
- buffer = (char *)malloc(1024 * sizeof(char));
- if (buffer == NULL) {
- perror("malloc");
- return EXIT_FAILURE;
- }
-
- strcpy(buffer, "这是使用malloc分配的内存");
- printf("%s\n", buffer);
-
- // 使用free释放内存
- free(buffer);
-
- return 0;
- }
复制代码- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/mman.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
- int main() {
- int fd;
- char *mapped;
- struct stat sb;
-
- // 打开文件
- fd = open("example.txt", O_RDONLY);
- if (fd == -1) {
- perror("open");
- return EXIT_FAILURE;
- }
-
- // 获取文件大小
- if (fstat(fd, &sb) == -1) {
- perror("fstat");
- close(fd);
- return EXIT_FAILURE;
- }
-
- // 使用mmap将文件映射到内存
- mapped = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (mapped == MAP_FAILED) {
- perror("mmap");
- close(fd);
- return EXIT_FAILURE;
- }
-
- // 直接访问映射的内存
- printf("文件内容: %.*s\n", (int)sb.st_size, mapped);
-
- // 使用munmap解除映射
- if (munmap(mapped, sb.st_size) == -1) {
- perror("munmap");
- }
-
- close(fd);
-
- return 0;
- }
复制代码
内存共享示例
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/mman.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #define SHM_SIZE 1024
- int main() {
- int *shared_data;
- pid_t pid;
-
- // 创建共享内存区域
- shared_data = mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
- if (shared_data == MAP_FAILED) {
- perror("mmap");
- return EXIT_FAILURE;
- }
-
- // 初始化共享数据
- *shared_data = 0;
-
- // 创建子进程
- pid = fork();
- if (pid == -1) {
- perror("fork");
- munmap(shared_data, SHM_SIZE);
- return EXIT_FAILURE;
- }
-
- if (pid == 0) {
- // 子进程
- printf("子进程: 读取共享数据 = %d\n", *shared_data);
- *shared_data = 42;
- printf("子进程: 修改共享数据为 %d\n", *shared_data);
- exit(EXIT_SUCCESS);
- } else {
- // 父进程
- wait(NULL); // 等待子进程结束
- printf("父进程: 读取共享数据 = %d\n", *shared_data);
- }
-
- // 解除共享内存映射
- if (munmap(shared_data, SHM_SIZE) == -1) {
- perror("munmap");
- return EXIT_FAILURE;
- }
-
- return 0;
- }
复制代码
进程控制
进程概念
进程是程序执行的实例,是操作系统进行资源分配和调度的基本单位。每个进程都有独立的地址空间、系统资源和执行状态。
进程创建与终止
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/wait.h>
- int main() {
- pid_t pid;
- int status;
-
- // 创建子进程
- pid = fork();
-
- if (pid == -1) {
- perror("fork");
- exit(EXIT_FAILURE);
- } else if (pid == 0) {
- // 子进程
- printf("子进程: PID = %d\n", getpid());
- // 使用execvp执行新程序
- char *args[] = {"echo", "Hello from child process", NULL};
- execvp("echo", args);
- // 如果execvp执行成功,下面的代码不会执行
- perror("execvp");
- exit(EXIT_FAILURE);
- } else {
- // 父进程
- printf("父进程: PID = %d, 子进程PID = %d\n", getpid(), pid);
- // 等待子进程结束
- wait(&status);
- printf("子进程结束,状态: %d\n", WEXITSTATUS(status));
- }
-
- return 0;
- }
复制代码
进程间通信
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/wait.h>
- int main() {
- int pipefd[2];
- pid_t pid;
- char buffer[1024];
- ssize_t bytes_read;
-
- // 创建管道
- if (pipe(pipefd) == -1) {
- perror("pipe");
- exit(EXIT_FAILURE);
- }
-
- // 创建子进程
- pid = fork();
-
- if (pid == -1) {
- perror("fork");
- close(pipefd[0]);
- close(pipefd[1]);
- exit(EXIT_FAILURE);
- } else if (pid == 0) {
- // 子进程 - 写入数据
- close(pipefd[0]); // 关闭读取端
-
- const char *message = "Hello from child process!";
- write(pipefd[1], message, strlen(message));
-
- close(pipefd[1]);
- exit(EXIT_SUCCESS);
- } else {
- // 父进程 - 读取数据
- close(pipefd[1]); // 关闭写入端
-
- bytes_read = read(pipefd[0], buffer, sizeof(buffer) - 1);
- if (bytes_read == -1) {
- perror("read");
- } else {
- buffer[bytes_read] = '\0';
- printf("父进程接收到: %s\n", buffer);
- }
-
- close(pipefd[0]);
- wait(NULL); // 等待子进程结束
- }
-
- return 0;
- }
复制代码- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #define SHM_KEY 1234
- #define SHM_SIZE 1024
- int main() {
- int shmid;
- char *shared_data;
- pid_t pid;
-
- // 创建共享内存
- shmid = shmget(SHM_KEY, SHM_SIZE, IPC_CREAT | 0666);
- if (shmid == -1) {
- perror("shmget");
- exit(EXIT_FAILURE);
- }
-
- // 将共享内存附加到进程地址空间
- shared_data = (char *)shmat(shmid, NULL, 0);
- if (shared_data == (char *)-1) {
- perror("shmat");
- exit(EXIT_FAILURE);
- }
-
- // 创建子进程
- pid = fork();
- if (pid == -1) {
- perror("fork");
- shmdt(shared_data);
- shmctl(shmid, IPC_RMID, NULL);
- exit(EXIT_FAILURE);
- }
-
- if (pid == 0) {
- // 子进程
- printf("子进程: 写入共享内存\n");
- sprintf(shared_data, "Hello from child process!");
- exit(EXIT_SUCCESS);
- } else {
- // 父进程
- wait(NULL); // 等待子进程结束
- printf("父进程: 从共享内存读取: %s\n", shared_data);
-
- // 分离共享内存
- shmdt(shared_data);
-
- // 删除共享内存
- shmctl(shmid, IPC_RMID, NULL);
- }
-
- return 0;
- }
复制代码
文件操作
Linux文件系统概述
Linux文件系统采用树形结构组织文件和目录,所有文件和设备都被视为文件。文件操作是Linux编程中最基本的操作之一。
基本文件操作
- #include <stdio.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <string.h>
- int main() {
- int fd;
- char buffer[1024];
- ssize_t bytes_read;
-
- // 打开文件
- fd = open("example.txt", O_RDONLY);
- if (fd == -1) {
- perror("open");
- return EXIT_FAILURE;
- }
-
- // 读取文件内容
- bytes_read = read(fd, buffer, sizeof(buffer) - 1);
- if (bytes_read == -1) {
- perror("read");
- close(fd);
- return EXIT_FAILURE;
- }
-
- buffer[bytes_read] = '\0'; // 确保字符串以null结尾
- printf("文件内容: %s\n", buffer);
-
- // 关闭文件
- if (close(fd) == -1) {
- perror("close");
- return EXIT_FAILURE;
- }
-
- return 0;
- }
复制代码- #include <stdio.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <string.h>
- int main() {
- int fd;
- const char *message = "Hello, Linux file programming!\n";
- ssize_t bytes_written;
-
- // 打开文件,如果不存在则创建,存在则截断
- fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (fd == -1) {
- perror("open");
- return EXIT_FAILURE;
- }
-
- // 写入数据
- bytes_written = write(fd, message, strlen(message));
- if (bytes_written == -1) {
- perror("write");
- close(fd);
- return EXIT_FAILURE);
- }
-
- printf("成功写入 %zd 字节\n", bytes_written);
-
- // 关闭文件
- if (close(fd) == -1) {
- perror("close");
- return EXIT_FAILURE;
- }
-
- return 0;
- }
复制代码
文件定位和截断
- #include <stdio.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <sys/types.h>
- int main() {
- int fd;
- off_t offset;
- char buffer[100];
- ssize_t bytes_read;
-
- // 打开文件
- fd = open("example.txt", O_RDWR);
- if (fd == -1) {
- perror("open");
- return EXIT_FAILURE;
- }
-
- // 读取前100个字节
- bytes_read = read(fd, buffer, sizeof(buffer) - 1);
- if (bytes_read == -1) {
- perror("read");
- close(fd);
- return EXIT_FAILURE;
- }
-
- buffer[bytes_read] = '\0';
- printf("读取的内容: %s\n", buffer);
-
- // 定位到文件开头
- offset = lseek(fd, 0, SEEK_SET);
- if (offset == -1) {
- perror("lseek");
- close(fd);
- return EXIT_FAILURE;
- }
-
- // 截断文件到50字节
- if (ftruncate(fd, 50) == -1) {
- perror("ftruncate");
- close(fd);
- return EXIT_FAILURE;
- }
-
- printf("文件已截断为50字节\n");
-
- // 关闭文件
- if (close(fd) == -1) {
- perror("close");
- return EXIT_FAILURE;
- }
-
- return 0;
- }
复制代码
目录操作
- #include <stdio.h>
- #include <stdlib.h>
- #include <dirent.h>
- #include <sys/stat.h>
- #include <unistd.h>
- void list_directory(const char *path) {
- DIR *dir;
- struct dirent *entry;
- struct stat file_stat;
- char full_path[1024];
-
- // 打开目录
- dir = opendir(path);
- if (dir == NULL) {
- perror("opendir");
- return;
- }
-
- printf("目录 %s 的内容:\n", path);
-
- // 读取目录项
- while ((entry = readdir(dir)) != NULL) {
- // 跳过 "." 和 ".."
- if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
- continue;
- }
-
- // 构建完整路径
- snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name);
-
- // 获取文件状态
- if (stat(full_path, &file_stat) == -1) {
- perror("stat");
- continue;
- }
-
- // 打印文件信息
- printf("%-20s", entry->d_name);
- if (S_ISDIR(file_stat.st_mode)) {
- printf("(目录)\n");
- } else if (S_ISREG(file_stat.st_mode)) {
- printf("(文件, 大小: %ld 字节)\n", file_stat.st_size);
- } else {
- printf("(其他类型)\n");
- }
- }
-
- // 关闭目录
- closedir(dir);
- }
- int main() {
- const char *path = ".";
- list_directory(path);
- return 0;
- }
复制代码
网络编程
网络编程基础
Linux网络编程主要基于Socket API,它提供了一套标准的接口用于网络通信。Socket编程可以分为TCP和UDP两种主要方式。
TCP Socket编程
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #define PORT 8080
- #define BUFFER_SIZE 1024
- int main() {
- int server_fd, client_fd;
- struct sockaddr_in address;
- int addrlen = sizeof(address);
- char buffer[BUFFER_SIZE] = {0};
- const char *message = "Hello from server";
-
- // 创建socket文件描述符
- if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
- perror("socket failed");
- exit(EXIT_FAILURE);
- }
-
- // 设置socket选项,允许地址重用
- int opt = 1;
- if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
- perror("setsockopt");
- exit(EXIT_FAILURE);
- }
-
- address.sin_family = AF_INET;
- address.sin_addr.s_addr = INADDR_ANY;
- address.sin_port = htons(PORT);
-
- // 绑定socket到指定端口
- if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
- perror("bind failed");
- exit(EXIT_FAILURE);
- }
-
- // 监听连接
- if (listen(server_fd, 3) < 0) {
- perror("listen");
- exit(EXIT_FAILURE);
- }
-
- printf("服务器正在监听端口 %d...\n", PORT);
-
- // 接受连接
- if ((client_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
- perror("accept");
- exit(EXIT_FAILURE);
- }
-
- // 读取客户端发送的数据
- ssize_t bytes_read = read(client_fd, buffer, BUFFER_SIZE);
- printf("客户端消息: %s\n", buffer);
-
- // 发送响应给客户端
- send(client_fd, message, strlen(message), 0);
- printf("响应消息已发送\n");
-
- // 关闭socket
- close(client_fd);
- close(server_fd);
-
- return 0;
- }
复制代码- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #define PORT 8080
- #define BUFFER_SIZE 1024
- int main() {
- int sock = 0;
- struct sockaddr_in serv_addr;
- char buffer[BUFFER_SIZE] = {0};
- const char *message = "Hello from client";
-
- // 创建socket文件描述符
- if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- printf("\n Socket creation error \n");
- return -1;
- }
-
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_port = htons(PORT);
-
- // 将IPv4地址从文本转换为二进制形式
- if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
- printf("\nInvalid address/ Address not supported \n");
- return -1;
- }
-
- // 连接到服务器
- if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
- printf("\nConnection Failed \n");
- return -1;
- }
-
- // 发送消息到服务器
- send(sock, message, strlen(message), 0);
- printf("消息已发送\n");
-
- // 读取服务器响应
- ssize_t bytes_read = read(sock, buffer, BUFFER_SIZE);
- printf("服务器响应: %s\n", buffer);
-
- // 关闭socket
- close(sock);
-
- return 0;
- }
复制代码
UDP Socket编程
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #define PORT 8080
- #define BUFFER_SIZE 1024
- int main() {
- int sockfd;
- char buffer[BUFFER_SIZE];
- struct sockaddr_in servaddr, cliaddr;
-
- // 创建socket文件描述符
- if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- perror("socket creation failed");
- exit(EXIT_FAILURE);
- }
-
- memset(&servaddr, 0, sizeof(servaddr));
- memset(&cliaddr, 0, sizeof(cliaddr));
-
- // 填充服务器信息
- servaddr.sin_family = AF_INET;
- servaddr.sin_addr.s_addr = INADDR_ANY;
- servaddr.sin_port = htons(PORT);
-
- // 绑定socket到指定端口
- if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
- perror("bind failed");
- exit(EXIT_FAILURE);
- }
-
- printf("UDP服务器正在监听端口 %d...\n", PORT);
-
- int len, n;
- len = sizeof(cliaddr);
-
- // 接收客户端消息
- n = recvfrom(sockfd, (char *)buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr *)&cliaddr, &len);
- buffer[n] = '\0';
- printf("客户端消息: %s\n", buffer);
-
- // 发送响应给客户端
- const char *response = "Hello from UDP server";
- sendto(sockfd, (const char *)response, strlen(response), MSG_CONFIRM, (const struct sockaddr *)&cliaddr, len);
- printf("响应消息已发送\n");
-
- // 关闭socket
- close(sockfd);
-
- return 0;
- }
复制代码- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #define PORT 8080
- #define BUFFER_SIZE 1024
- int main() {
- int sockfd;
- char buffer[BUFFER_SIZE];
- struct sockaddr_in servaddr;
-
- // 创建socket文件描述符
- if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- perror("socket creation failed");
- exit(EXIT_FAILURE);
- }
-
- memset(&servaddr, 0, sizeof(servaddr));
-
- // 填充服务器信息
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(PORT);
- servaddr.sin_addr.s_addr = INADDR_ANY;
-
- // 将IPv4地址从文本转换为二进制形式
- inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
-
- const char *message = "Hello from UDP client";
-
- // 发送消息到服务器
- sendto(sockfd, (const char *)message, strlen(message), MSG_CONFIRM, (const struct sockaddr *)&servaddr, sizeof(servaddr));
- printf("消息已发送\n");
-
- // 接收服务器响应
- int n, len;
- len = sizeof(servaddr);
- n = recvfrom(sockfd, (char *)buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr *)&servaddr, &len);
- buffer[n] = '\0';
- printf("服务器响应: %s\n", buffer);
-
- // 关闭socket
- close(sockfd);
-
- return 0;
- }
复制代码
多线程开发
线程概念
线程是进程内的执行单元,共享进程的资源。多线程编程可以提高程序的并发性和响应性,特别适合I/O密集型任务。
POSIX线程(Pthreads)
- #include <stdio.h>
- #include <stdlib.h>
- #include <pthread.h>
- #define NUM_THREADS 5
- // 线程函数
- void *thread_function(void *arg) {
- int thread_id = *((int *)arg);
- printf("线程 %d: 正在运行\n", thread_id);
-
- // 模拟工作
- for (int i = 0; i < 3; i++) {
- printf("线程 %d: 工作中... %d\n", thread_id, i);
- sleep(1);
- }
-
- printf("线程 %d: 完成\n", thread_id);
- pthread_exit(NULL);
- }
- int main() {
- pthread_t threads[NUM_THREADS];
- int thread_args[NUM_THREADS];
- int rc;
-
- // 创建线程
- for (int i = 0; i < NUM_THREADS; i++) {
- thread_args[i] = i;
- printf("主线程: 创建线程 %d\n", i);
-
- rc = pthread_create(&threads[i], NULL, thread_function, &thread_args[i]);
- if (rc) {
- printf("错误: 无法创建线程 %d, 错误码: %d\n", i, rc);
- exit(EXIT_FAILURE);
- }
- }
-
- // 等待所有线程完成
- for (int i = 0; i < NUM_THREADS; i++) {
- rc = pthread_join(threads[i], NULL);
- if (rc) {
- printf("错误: 无法加入线程 %d, 错误码: %d\n", i, rc);
- exit(EXIT_FAILURE);
- }
- printf("主线程: 线程 %d 已完成\n", i);
- }
-
- printf("主线程: 所有线程已完成\n");
- pthread_exit(NULL);
-
- return 0;
- }
复制代码
线程同步
- #include <stdio.h>
- #include <stdlib.h>
- #include <pthread.h>
- #define NUM_THREADS 5
- #define ITERATIONS 1000000
- int counter = 0;
- pthread_mutex_t mutex;
- // 线程函数
- void *thread_function(void *arg) {
- int thread_id = *((int *)arg);
-
- for (int i = 0; i < ITERATIONS; i++) {
- // 锁定互斥量
- pthread_mutex_lock(&mutex);
-
- // 临界区 - 访问共享资源
- counter++;
-
- // 解锁互斥量
- pthread_mutex_unlock(&mutex);
- }
-
- printf("线程 %d: 完成\n", thread_id);
- pthread_exit(NULL);
- }
- int main() {
- pthread_t threads[NUM_THREADS];
- int thread_args[NUM_THREADS];
- int rc;
-
- // 初始化互斥量
- pthread_mutex_init(&mutex, NULL);
-
- // 创建线程
- for (int i = 0; i < NUM_THREADS; i++) {
- thread_args[i] = i;
- printf("主线程: 创建线程 %d\n", i);
-
- rc = pthread_create(&threads[i], NULL, thread_function, &thread_args[i]);
- if (rc) {
- printf("错误: 无法创建线程 %d, 错误码: %d\n", i, rc);
- exit(EXIT_FAILURE);
- }
- }
-
- // 等待所有线程完成
- for (int i = 0; i < NUM_THREADS; i++) {
- rc = pthread_join(threads[i], NULL);
- if (rc) {
- printf("错误: 无法加入线程 %d, 错误码: %d\n", i, rc);
- exit(EXIT_FAILURE);
- }
- }
-
- // 销毁互斥量
- pthread_mutex_destroy(&mutex);
-
- printf("主线程: 所有线程已完成\n");
- printf("最终计数器值: %d (预期值: %d)\n", counter, NUM_THREADS * ITERATIONS);
-
- return 0;
- }
复制代码- #include <stdio.h>
- #include <stdlib.h>
- #include <pthread.h>
- #define BUFFER_SIZE 10
- #define NUM_ITEMS 20
- int buffer[BUFFER_SIZE];
- int count = 0;
- int in = 0;
- int out = 0;
- pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- pthread_cond_t cond_producer = PTHREAD_COND_INITIALIZER;
- pthread_cond_t cond_consumer = PTHREAD_COND_INITIALIZER;
- // 生产者函数
- void *producer(void *arg) {
- int producer_id = *((int *)arg);
- int item;
-
- for (int i = 0; i < NUM_ITEMS; i++) {
- item = producer_id * 100 + i; // 生成项目
-
- // 锁定互斥量
- pthread_mutex_lock(&mutex);
-
- // 如果缓冲区满,等待消费者消费
- while (count == BUFFER_SIZE) {
- printf("生产者 %d: 缓冲区满,等待...\n", producer_id);
- pthread_cond_wait(&cond_producer, &mutex);
- }
-
- // 生产项目
- buffer[in] = item;
- in = (in + 1) % BUFFER_SIZE;
- count++;
-
- printf("生产者 %d: 生产项目 %d\n", producer_id, item);
-
- // 通知消费者有新项目
- pthread_cond_signal(&cond_consumer);
-
- // 解锁互斥量
- pthread_mutex_unlock(&mutex);
-
- // 模拟生产时间
- usleep(100000); // 100毫秒
- }
-
- printf("生产者 %d: 完成\n", producer_id);
- pthread_exit(NULL);
- }
- // 消费者函数
- void *consumer(void *arg) {
- int consumer_id = *((int *)arg);
- int item;
-
- for (int i = 0; i < NUM_ITEMS; i++) {
- // 锁定互斥量
- pthread_mutex_lock(&mutex);
-
- // 如果缓冲区空,等待生产者生产
- while (count == 0) {
- printf("消费者 %d: 缓冲区空,等待...\n", consumer_id);
- pthread_cond_wait(&cond_consumer, &mutex);
- }
-
- // 消费项目
- item = buffer[out];
- out = (out + 1) % BUFFER_SIZE;
- count--;
-
- printf("消费者 %d: 消费项目 %d\n", consumer_id, item);
-
- // 通知生产者有空间
- pthread_cond_signal(&cond_producer);
-
- // 解锁互斥量
- pthread_mutex_unlock(&mutex);
-
- // 模拟消费时间
- usleep(200000); // 200毫秒
- }
-
- printf("消费者 %d: 完成\n", consumer_id);
- pthread_exit(NULL);
- }
- int main() {
- pthread_t producers[2];
- pthread_t consumers[2];
- int producer_ids[2] = {1, 2};
- int consumer_ids[2] = {1, 2};
- int rc;
-
- // 创建生产者线程
- for (int i = 0; i < 2; i++) {
- rc = pthread_create(&producers[i], NULL, producer, &producer_ids[i]);
- if (rc) {
- printf("错误: 无法创建生产者线程 %d, 错误码: %d\n", i, rc);
- exit(EXIT_FAILURE);
- }
- }
-
- // 创建消费者线程
- for (int i = 0; i < 2; i++) {
- rc = pthread_create(&consumers[i], NULL, consumer, &consumer_ids[i]);
- if (rc) {
- printf("错误: 无法创建消费者线程 %d, 错误码: %d\n", i, rc);
- exit(EXIT_FAILURE);
- }
- }
-
- // 等待所有线程完成
- for (int i = 0; i < 2; i++) {
- pthread_join(producers[i], NULL);
- pthread_join(consumers[i], NULL);
- }
-
- // 销毁互斥量和条件变量
- pthread_mutex_destroy(&mutex);
- pthread_cond_destroy(&cond_producer);
- pthread_cond_destroy(&cond_consumer);
-
- printf("主线程: 所有线程已完成\n");
-
- return 0;
- }
复制代码
实践案例:多线程Web服务器
下面是一个结合了前面介绍的多项技术的综合案例:一个简单的多线程Web服务器。
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <pthread.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #define PORT 8080
- #define BUFFER_SIZE 4096
- #define THREAD_POOL_SIZE 10
- // 线程池结构
- typedef struct {
- pthread_t *threads;
- int thread_count;
- int queue_size;
- int front;
- int rear;
- int count;
- int *client_fds;
- pthread_mutex_t lock;
- pthread_cond_t notify;
- int shutdown;
- } thread_pool_t;
- // HTTP请求结构
- typedef struct {
- int client_fd;
- struct sockaddr_in client_addr;
- } http_request_t;
- // 初始化线程池
- thread_pool_t *thread_pool_create(int thread_count, int queue_size) {
- thread_pool_t *pool = (thread_pool_t *)malloc(sizeof(thread_pool_t));
- if (pool == NULL) {
- perror("malloc");
- return NULL;
- }
-
- pool->thread_count = thread_count;
- pool->queue_size = queue_size;
- pool->front = 0;
- pool->rear = 0;
- pool->count = 0;
- pool->shutdown = 0;
-
- // 初始化互斥量和条件变量
- pthread_mutex_init(&(pool->lock), NULL);
- pthread_cond_init(&(pool->notify), NULL);
-
- // 分配线程数组
- pool->threads = (pthread_t *)malloc(sizeof(pthread_t) * thread_count);
- if (pool->threads == NULL) {
- perror("malloc");
- free(pool);
- return NULL;
- }
-
- // 分配客户端文件描述符数组
- pool->client_fds = (int *)malloc(sizeof(int) * queue_size);
- if (pool->client_fds == NULL) {
- perror("malloc");
- free(pool->threads);
- free(pool);
- return NULL;
- }
-
- // 创建工作线程
- for (int i = 0; i < thread_count; i++) {
- if (pthread_create(&(pool->threads[i]), NULL, thread_pool_worker, (void *)pool) != 0) {
- perror("pthread_create");
- free(pool->threads);
- free(pool->client_fds);
- free(pool);
- return NULL;
- }
- }
-
- return pool;
- }
- // 工作线程函数
- void *thread_pool_worker(void *arg) {
- thread_pool_t *pool = (thread_pool_t *)arg;
- int client_fd;
-
- while (1) {
- // 锁定互斥量
- pthread_mutex_lock(&(pool->lock));
-
- // 等待任务或关闭信号
- while (pool->count == 0 && !pool->shutdown) {
- pthread_cond_wait(&(pool->notify), &(pool->lock));
- }
-
- // 如果线程池关闭且没有任务,退出线程
- if (pool->shutdown && pool->count == 0) {
- pthread_mutex_unlock(&(pool->lock));
- pthread_exit(NULL);
- }
-
- // 获取客户端文件描述符
- client_fd = pool->client_fds[pool->front];
- pool->front = (pool->front + 1) % pool->queue_size;
- pool->count--;
-
- // 解锁互斥量
- pthread_mutex_unlock(&(pool->lock));
-
- // 处理HTTP请求
- handle_http_request(client_fd);
-
- // 关闭客户端连接
- close(client_fd);
- }
-
- pthread_exit(NULL);
- return NULL;
- }
- // 添加任务到线程池
- int thread_pool_add_task(thread_pool_t *pool, int client_fd) {
- int err = 0;
-
- // 锁定互斥量
- pthread_mutex_lock(&(pool->lock));
-
- // 检查队列是否已满
- if (pool->count == pool->queue_size) {
- err = -1;
- } else {
- // 添加客户端文件描述符到队列
- pool->client_fds[pool->rear] = client_fd;
- pool->rear = (pool->rear + 1) % pool->queue_size;
- pool->count++;
-
- // 通知工作线程有新任务
- pthread_cond_signal(&(pool->notify));
- }
-
- // 解锁互斥量
- pthread_mutex_unlock(&(pool->lock));
-
- return err;
- }
- // 销毁线程池
- void thread_pool_destroy(thread_pool_t *pool) {
- if (pool == NULL) {
- return;
- }
-
- // 锁定互斥量
- pthread_mutex_lock(&(pool->lock));
-
- // 设置关闭标志
- pool->shutdown = 1;
-
- // 解锁互斥量
- pthread_mutex_unlock(&(pool->lock));
-
- // 通知所有工作线程
- pthread_cond_broadcast(&(pool->notify));
-
- // 等待所有工作线程结束
- for (int i = 0; i < pool->thread_count; i++) {
- pthread_join(pool->threads[i], NULL);
- }
-
- // 销毁互斥量和条件变量
- pthread_mutex_destroy(&(pool->lock));
- pthread_cond_destroy(&(pool->notify));
-
- // 释放内存
- free(pool->threads);
- free(pool->client_fds);
- free(pool);
- }
- // 处理HTTP请求
- void handle_http_request(int client_fd) {
- char buffer[BUFFER_SIZE];
- ssize_t bytes_read;
-
- // 读取HTTP请求
- bytes_read = read(client_fd, buffer, BUFFER_SIZE - 1);
- if (bytes_read <= 0) {
- return;
- }
-
- buffer[bytes_read] = '\0';
- printf("收到请求:\n%s\n", buffer);
-
- // 解析请求方法
- char method[16];
- char path[256];
- sscanf(buffer, "%15s %255s", method, path);
-
- // 处理GET请求
- if (strcmp(method, "GET") == 0) {
- // 默认页面
- if (strcmp(path, "/") == 0) {
- strcpy(path, "/index.html");
- }
-
- // 构建文件路径
- char file_path[512];
- snprintf(file_path, sizeof(file_path), "public%s", path);
-
- // 检查文件是否存在
- struct stat file_stat;
- if (stat(file_path, &file_stat) == -1) {
- // 文件不存在,返回404
- send_http_response(client_fd, 404, "Not Found", "text/html", "<html><body><h1>404 Not Found</h1></body></html>");
- return;
- }
-
- // 如果是目录,尝试查找index.html
- if (S_ISDIR(file_stat.st_mode)) {
- strcat(file_path, "/index.html");
- if (stat(file_path, &file_stat) == -1) {
- send_http_response(client_fd, 404, "Not Found", "text/html", "<html><body><h1>404 Not Found</h1></body></html>");
- return;
- }
- }
-
- // 读取文件内容
- int file_fd = open(file_path, O_RDONLY);
- if (file_fd == -1) {
- send_http_response(client_fd, 500, "Internal Server Error", "text/html", "<html><body><h1>500 Internal Server Error</h1></body></html>");
- return;
- }
-
- // 确定MIME类型
- const char *mime_type = "text/plain";
- if (strstr(file_path, ".html") != NULL) {
- mime_type = "text/html";
- } else if (strstr(file_path, ".css") != NULL) {
- mime_type = "text/css";
- } else if (strstr(file_path, ".js") != NULL) {
- mime_type = "application/javascript";
- } else if (strstr(file_path, ".jpg") != NULL || strstr(file_path, ".jpeg") != NULL) {
- mime_type = "image/jpeg";
- } else if (strstr(file_path, ".png") != NULL) {
- mime_type = "image/png";
- } else if (strstr(file_path, ".gif") != NULL) {
- mime_type = "image/gif";
- }
-
- // 发送HTTP响应头
- char header[BUFFER_SIZE];
- snprintf(header, sizeof(header),
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: %s\r\n"
- "Content-Length: %ld\r\n"
- "\r\n",
- mime_type, file_stat.st_size);
-
- write(client_fd, header, strlen(header));
-
- // 发送文件内容
- char file_buffer[BUFFER_SIZE];
- ssize_t bytes_read;
- while ((bytes_read = read(file_fd, file_buffer, BUFFER_SIZE)) > 0) {
- write(client_fd, file_buffer, bytes_read);
- }
-
- close(file_fd);
- } else {
- // 不支持的HTTP方法
- send_http_response(client_fd, 405, "Method Not Allowed", "text/html", "<html><body><h1>405 Method Not Allowed</h1></body></html>");
- }
- }
- // 发送HTTP响应
- void send_http_response(int client_fd, int status_code, const char *status_text, const char *content_type, const char *content) {
- char response[BUFFER_SIZE];
- snprintf(response, sizeof(response),
- "HTTP/1.1 %d %s\r\n"
- "Content-Type: %s\r\n"
- "Content-Length: %ld\r\n"
- "\r\n"
- "%s",
- status_code, status_text, content_type, strlen(content), content);
-
- write(client_fd, response, strlen(response));
- }
- int main() {
- int server_fd, client_fd;
- struct sockaddr_in address;
- int addrlen = sizeof(address);
-
- // 创建线程池
- thread_pool_t *pool = thread_pool_create(THREAD_POOL_SIZE, 100);
- if (pool == NULL) {
- fprintf(stderr, "无法创建线程池\n");
- return EXIT_FAILURE;
- }
-
- // 创建socket文件描述符
- if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
- perror("socket failed");
- thread_pool_destroy(pool);
- return EXIT_FAILURE;
- }
-
- // 设置socket选项,允许地址重用
- int opt = 1;
- if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
- perror("setsockopt");
- thread_pool_destroy(pool);
- return EXIT_FAILURE;
- }
-
- address.sin_family = AF_INET;
- address.sin_addr.s_addr = INADDR_ANY;
- address.sin_port = htons(PORT);
-
- // 绑定socket到指定端口
- if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
- perror("bind failed");
- thread_pool_destroy(pool);
- return EXIT_FAILURE;
- }
-
- // 监听连接
- if (listen(server_fd, 10) < 0) {
- perror("listen");
- thread_pool_destroy(pool);
- return EXIT_FAILURE;
- }
-
- printf("服务器正在监听端口 %d...\n", PORT);
-
- // 主循环:接受连接并添加到线程池
- while (1) {
- // 接受连接
- if ((client_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
- perror("accept");
- continue;
- }
-
- printf("新连接: %s:%d\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));
-
- // 添加任务到线程池
- if (thread_pool_add_task(pool, client_fd) != 0) {
- fprintf(stderr, "线程池队列已满,拒绝连接\n");
- close(client_fd);
- }
- }
-
- // 销毁线程池
- thread_pool_destroy(pool);
-
- // 关闭服务器socket
- close(server_fd);
-
- return 0;
- }
复制代码
这个多线程Web服务器结合了前面介绍的多种技术:
1. 网络编程:使用Socket API处理网络连接
2. 多线程开发:使用线程池处理并发请求
3. 文件操作:读取和发送静态文件
4. 进程控制:虽然是多线程,但也涉及并发概念
5. 系统调用:使用各种系统调用进行I/O操作
学习资源推荐
书籍
1. 《Linux/UNIX系统编程手册》(The Linux Programming Interface) - Michael Kerrisk
2. 《UNIX环境高级编程》(Advanced Programming in the UNIX Environment) - W. Richard Stevens
3. 《Linux多线程服务端编程》 - 陈硕
4. 《TCP/IP详解 卷一:协议》 - W. Richard Stevens
在线资源
1. Linux手册页 (man pages)
2. Linux内核文档 (https://www.kernel.org/doc/)
3. GNU C库参考手册 (https://www.gnu.org/software/libc/manual/)
4. Linux Foundation培训课程 (https://training.linuxfoundation.org/)
实践项目
1. 实现一个简单的Shell
2. 开发一个网络聊天室
3. 编写一个多线程文件服务器
4. 实现一个简单的数据库系统
5. 开发一个Web服务器
总结
Linux高级编程是系统开发的核心技能,涉及系统调用、内存管理、进程控制、文件操作、网络编程和多线程开发等多个方面。通过深入理解这些概念和技术,并结合实际项目进行实践,可以快速提升Linux系统开发能力。
本文详细介绍了Linux高级编程的各个方面,并提供了丰富的代码示例,帮助读者理解和应用这些技术。希望读者能够通过学习和实践,掌握Linux高级编程的核心技能,成为一名优秀的Linux系统开发人员。
记住,编程技能的提升需要不断的学习和实践。继续探索Linux系统的奥秘,挑战更复杂的项目,你的Linux系统开发能力将不断提升。 |
|