69天探索操作系统-第9天:线程与进程比较 - 在 C 中实现并发系统

1.介绍

了解线程和进程之间的差异对于设计高效的并发应用程序至关重要。本文提供了线程和进程的详细比较,重点关注它们的实现、性能特征和适当的用例。

2.核心概念

基本差异

  1. 内存空间: 进程中的内存空间是完全独立和隔离的。每个进程都有自己的地址空间,包括代码、数据和堆段。例如,如果进程A的变量'x'位于地址0x1000,那么它与进程B在同一地址的变量'x'完全不同。

  2. 资源所有者: 进程独立拥有和控制其所有资源。当一个进程创建文件句柄时,该句柄不能直接被其他进程访问,除非有明确的共享机制。不过,线程可以在同一个进程中共享资源,从而使资源共享更加直观。

  3. 上下文切换开销: 进程上下文切换需要保存和加载整个内存映射、缓存内容和CPU寄存器。线程上下文切换只需要保存和恢复CPU寄存器和栈指针,因此开销要轻得多。

  4. 创建时间: 创建一个新进程涉及复制父进程的全部内存空间和资源。线程的创建只需要分配一个新的堆栈和线程特定的数据结构。

以下是演示:

 

c

代码解读

复制代码

#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <sys/time.h> #include <unistd.h> #include <sys/wait.h> // Timing structure typedef struct { struct timeval start; struct timeval end; } timing_t; // Function to measure process creation time void measure_process_creation() { timing_t timing; gettimeofday(&timing.start, NULL); pid_t pid = fork(); if (pid == 0) { // Child process exit(0); } else { // Parent process wait(NULL); } gettimeofday(&timing.end, NULL); long microseconds = (timing.end.tv_sec - timing.start.tv_sec) * 1000000 + (timing.end.tv_usec - timing.start.tv_usec); printf("Process creation time: %ld microseconds\n", microseconds); } // Function for thread creation measurement void* thread_function(void* arg) { return NULL; } void measure_thread_creation() { timing_t timing; pthread_t thread; gettimeofday(&timing.start, NULL); pthread_create(&thread, NULL, thread_function, NULL); pthread_join(thread, NULL); gettimeofday(&timing.end, NULL); long microseconds = (timing.end.tv_sec - timing.start.tv_sec) * 1000000 + (timing.end.tv_usec - timing.start.tv_usec); printf("Thread creation time: %ld microseconds\n", microseconds); } int main() { measure_process_creation(); measure_thread_creation(); return 0; }

3. 内存架构比较

内存布局分析

 

c

代码解读

复制代码

#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> #include <sys/mman.h> // Shared data structure typedef struct { int process_value; int thread_value; } shared_data_t; // Global variables shared_data_t* shared_memory; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void* thread_function(void* arg) { // Thread can access process memory directly shared_memory->thread_value++; return NULL; } int main() { // Create shared memory for processes shared_memory = mmap(NULL, sizeof(shared_data_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); shared_memory->process_value = 0; shared_memory->thread_value = 0; // Create process pid_t pid = fork(); if (pid == 0) { // Child process shared_memory->process_value++; exit(0); } else { // Parent process pthread_t thread; pthread_create(&thread, NULL, thread_function, NULL); pthread_join(thread, NULL); wait(NULL); printf("Process value: %d\n", shared_memory->process_value); printf("Thread value: %d\n", shared_memory->thread_value); munmap(shared_memory, sizeof(shared_data_t)); } return 0; }

4. 性能分析

CPU 利用情况

  1. 进程调度开销: 由于内存管理单元(MMU)更新和TLB刷新,需要更多的CPU时间来进行上下文切换。这里的基准测试如下:
 

c

代码解读

复制代码

#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <sys/time.h> #include <unistd.h> #define NUM_ITERATIONS 1000000 void measure_context_switch_overhead() { int pipe_fd[2]; pipe(pipe_fd); struct timeval start, end; char buffer[1]; gettimeofday(&start, NULL); pid_t pid = fork(); if (pid == 0) { // Child process for (int i = 0; i < NUM_ITERATIONS; i++) { read(pipe_fd[0], buffer, 1); write(pipe_fd[1], "x", 1); } exit(0); } else { // Parent process for (int i = 0; i < NUM_ITERATIONS; i++) { write(pipe_fd[1], "x", 1); read(pipe_fd[0], buffer, 1); } } gettimeofday(&end, NULL); long microseconds = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec); printf("Average context switch time: %f microseconds\n", (float)microseconds / (NUM_ITERATIONS * 2)); } int main() { measure_context_switch_overhead(); return 0; }

  1. 内存访问模式: 线程共享相同的地址空间,从而提高了缓存利用率。 以下是一个演示:
 

c

代码解读

复制代码

#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <sys/time.h> #define ARRAY_SIZE 10000000 #define NUM_THREADS 4 double* shared_array; void* thread_function(void* arg) { int thread_id = *(int*)arg; int chunk_size = ARRAY_SIZE / NUM_THREADS; int start = thread_id * chunk_size; int end = start + chunk_size; for (int i = start; i < end; i++) { shared_array[i] = shared_array[i] * 2.0; } return NULL; } int main() { shared_array = malloc(ARRAY_SIZE * sizeof(double)); pthread_t threads[NUM_THREADS]; int thread_ids[NUM_THREADS]; // Initialize array for (int i = 0; i < ARRAY_SIZE; i++) { shared_array[i] = (double)i; } struct timeval start, end; gettimeofday(&start, NULL); // Create threads for (int i = 0; i < NUM_THREADS; i++) { thread_ids[i] = i; pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]); } // Wait for threads for (int i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } gettimeofday(&end, NULL); long microseconds = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec); printf("Thread processing time: %ld microseconds\n", microseconds); free(shared_array); return 0; }

5.通信机制

进程间通信 (IPC)

  1. 管道和命名管道: 进程通过管道进行通信,管道需要系统调用和数据复制。 示例:
 

c

代码解读

复制代码

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #define BUFFER_SIZE 1024 void demonstrate_pipe_communication() { int pipe_fd[2]; char buffer[BUFFER_SIZE]; if (pipe(pipe_fd) == -1) { perror("pipe"); exit(1); } pid_t pid = fork(); if (pid == 0) { // Child process close(pipe_fd[1]); // Close write end ssize_t bytes_read = read(pipe_fd[0], buffer, BUFFER_SIZE); printf("Child received: %s\n", buffer); close(pipe_fd[0]); exit(0); } else { // Parent process close(pipe_fd[0]); // Close read end const char* message = "Hello from parent!"; write(pipe_fd[1], message, strlen(message) + 1); close(pipe_fd[1]); wait(NULL); } } int main() { demonstrate_pipe_communication(); return 0; }

2.共享内存: 进程可以共享内存区域以加快通信

 

c

代码解读

复制代码

#include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #define SHM_NAME "/my_shm" #define SHM_SIZE 1024 void demonstrate_shared_memory() { int shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666); ftruncate(shm_fd, SHM_SIZE); void* shm_ptr = mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); pid_t pid = fork(); if (pid == 0) { // Child process sleep(1); // Ensure parent writes first printf("Child read: %s\n", (char*)shm_ptr); exit(0); } else { // Parent process sprintf(shm_ptr, "Hello from shared memory!"); wait(NULL); munmap(shm_ptr, SHM_SIZE); shm_unlink(SHM_NAME); } } int main() { demonstrate_shared_memory(); return 0; }

线程间通信

线程可以通过共享内存直接进行通信:

 

c

代码解读

复制代码

#include <stdio.h> #include <pthread.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int shared_data = 0; int data_ready = 0; void* producer(void* arg) { pthread_mutex_lock(&mutex); shared_data = 42; data_ready = 1; pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); return NULL; } void* consumer(void* arg) { pthread_mutex_lock(&mutex); while (!data_ready) { pthread_cond_wait(&cond, &mutex); } printf("Received: %d\n", shared_data); pthread_mutex_unlock(&mutex); return NULL; } int main() { pthread_t prod_thread, cons_thread; pthread_create(&cons_thread, NULL, consumer, NULL); pthread_create(&prod_thread, NULL, producer, NULL); pthread_join(prod_thread, NULL); pthread_join(cons_thread, NULL); pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); return 0; }

6.资源管理

进程资源

每个进程都有自己的:

  • 文件描述符
  • 内存映射
  • 信号处理器
  • 进程 ID
  • 用户和组 ID

线程资源

线程共享的资源:

  • 地址空间
  • 文件描述符
  • 信号处理器
  • 当前工作目录

线程独有的资源:

  • 堆栈
  • 线程ID
  • 信号掩码
  • errno 变量

7.实现示例

这里有一个综合示例,展示了对于同一任务的进程和线程实现:

 

c

代码解读

复制代码

#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> #include <sys/wait.h> #include <sys/time.h> #define ARRAY_SIZE 10000000 #define NUM_WORKERS 4 // Shared data structure typedef struct { double* array; int start; int end; } work_unit_t; // Thread worker function void* thread_worker(void* arg) { work_unit_t* unit = (work_unit_t*)arg; for (int i = unit->start; i < unit->end; i++) { unit->array[i] = unit->array[i] * 2.0; } return NULL; } // Process worker function void process_worker(double* array, int start, int end) { for (int i = start; i < end; i++) { array[i] = array[i] * 2.0; } } // Thread implementation void thread_implementation() { double* array = malloc(ARRAY_SIZE * sizeof(double)); pthread_t threads[NUM_WORKERS]; work_unit_t units[NUM_WORKERS]; // Initialize array for (int i = 0; i < ARRAY_SIZE; i++) { array[i] = (double)i; } struct timeval start, end; gettimeofday(&start, NULL); // Create threads int chunk_size = ARRAY_SIZE / NUM_WORKERS; for (int i = 0; i < NUM_WORKERS; i++) { units[i].array = array; units[i].start = i * chunk_size; units[i].end = (i == NUM_WORKERS - 1) ? ARRAY_SIZE : (i + 1) * chunk_size; pthread_create(&threads[i], NULL, thread_worker, &units[i]); } // Wait for threads for (int i = 0; i < NUM_WORKERS; i++) { pthread_join(threads[i], NULL); } gettimeofday(&end, NULL); long microseconds = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec); printf("Thread implementation time: %ld microseconds\n", microseconds); free(array); } // Process implementation void process_implementation() { double* array = mmap(NULL, ARRAY_SIZE * sizeof(double), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); // Initialize array for (int i = 0; i < ARRAY_SIZE; i++) { array[i] = (double)i; } struct timeval start, end; gettimeofday(&start, NULL); // Create processes int chunk_size = ARRAY_SIZE / NUM_WORKERS; for (int i = 0; i < NUM_WORKERS; i++) { pid_t pid = fork(); if (pid == 0) { // Child process int start = i * chunk_size; int end = (i == NUM_WORKERS - 1) ? ARRAY_SIZE : (i + 1) * chunk_size; process_worker(array, start, end); exit(0); } } // Wait for all child processes for (int i = 0; i < NUM_WORKERS; i++) { wait(NULL); } gettimeofday(&end, NULL); long microseconds = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec); printf("Process implementation time: %ld microseconds\n", microseconds); munmap(array, ARRAY_SIZE * sizeof(double)); } int main() { printf("Running thread implementation...\n"); thread_implementation(); printf("\nRunning process implementation...\n"); process_implementation(); return 0; }

8.使用案例分析

什么时候使用进程

  1. 隔离要求:进程在需要组件间强烈隔离时非常理想。例如,网页浏览器为每个标签页使用独立的进程,以防止一个标签页的崩溃影响其他标签页。 2.安全考虑:处理敏感数据时,通过内存隔离的过程提供更好的安全保障。举例用例:
 

c

代码解读

复制代码

#include <stdio.h> #include <unistd.h> #include <sys/mman.h> void secure_processing() { // Sensitive data in isolated process char* sensitive_data = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); sprintf(sensitive_data, "SECRET_KEY=12345"); // Process the data in isolation pid_t pid = fork(); if (pid == 0) { // Child process - isolated memory space printf("Child process handling sensitive data\n"); // Process sensitive_data here munmap(sensitive_data, 4096); exit(0); } else { wait(NULL); munmap(sensitive_data, 4096); } }

什么时候使用线程

1.共享资源访问: 线程在多个执行单元需要频繁共享资源时表现得更好

 

c

代码解读

复制代码

#include <pthread.h> #include <stdio.h> typedef struct { int* shared_counter; pthread_mutex_t* mutex; } shared_resource_t; void* increment_counter(void* arg) { shared_resource_t* resource = (shared_resource_t*)arg; for (int i = 0; i < 1000000; i++) { pthread_mutex_lock(resource->mutex); (*resource->shared_counter)++; pthread_mutex_unlock(resource->mutex); } return NULL; } void demonstrate_shared_resource() { int counter = 0; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; shared_resource_t resource = {&counter, &mutex}; pthread_t threads[4]; for (int i = 0; i < 4; i++) { pthread_create(&threads[i], NULL, increment_counter, &resource); } for (int i = 0; i < 4; i++) { pthread_join(threads[i], NULL); } printf("Final counter value: %d\n", counter); pthread_mutex_destroy(&mutex); }

  1. 实时通信: 线程在需要频繁通信的场景中非常高效:
 

c

代码解读

复制代码

#include <pthread.h> #include <stdio.h> #include <unistd.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t data_cond = PTHREAD_COND_INITIALIZER; int data_ready = 0; double shared_data = 0.0; void* real_time_producer(void* arg) { for (int i = 0; i < 10; i++) { pthread_mutex_lock(&mutex); shared_data = i * 1.5; data_ready = 1; pthread_cond_signal(&data_cond); pthread_mutex_unlock(&mutex); usleep(100000); // 100ms } return NULL; } void* real_time_consumer(void* arg) { while (1) { pthread_mutex_lock(&mutex); while (!data_ready) { pthread_cond_wait(&data_cond, &mutex); } printf("Received data: %f\n", shared_data); data_ready = 0; pthread_mutex_unlock(&mutex); } return NULL; }

9. 实际演示

以下是矩阵乘法过程中进程和线程性能比较的真实示例:

 

c

代码解读

复制代码

#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <sys/mman.h> #include <sys/wait.h> #include <sys/time.h> #define MATRIX_SIZE 1000 #define NUM_WORKERS 4 typedef struct { double* a; double* b; double* c; int start_row; int end_row; } matrix_work_t; void* thread_matrix_multiply(void* arg) { matrix_work_t* work = (matrix_work_t*)arg; for (int i = work->start_row; i < work->end_row; i++) { for (int j = 0; j < MATRIX_SIZE; j++) { double sum = 0.0; for (int k = 0; k < MATRIX_SIZE; k++) { sum += work->a[i * MATRIX_SIZE + k] * work->b[k * MATRIX_SIZE + j]; } work->c[i * MATRIX_SIZE + j] = sum; } } return NULL; } void process_matrix_multiply(double* a, double* b, double* c, int start_row, int end_row) { for (int i = start_row; i < end_row; i++) { for (int j = 0; j < MATRIX_SIZE; j++) { double sum = 0.0; for (int k = 0; k < MATRIX_SIZE; k++) { sum += a[i * MATRIX_SIZE + k] * b[k * MATRIX_SIZE + j]; } c[i * MATRIX_SIZE + j] = sum; } } } void compare_performance() { // Allocate matrices size_t matrix_bytes = MATRIX_SIZE * MATRIX_SIZE * sizeof(double); double* a = mmap(NULL, matrix_bytes, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); double* b = mmap(NULL, matrix_bytes, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); double* c = mmap(NULL, matrix_bytes, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); // Initialize matrices for (int i = 0; i < MATRIX_SIZE * MATRIX_SIZE; i++) { a[i] = (double)rand() / RAND_MAX; b[i] = (double)rand() / RAND_MAX; } struct timeval start, end; // Thread implementation gettimeofday(&start, NULL); pthread_t threads[NUM_WORKERS]; matrix_work_t thread_work[NUM_WORKERS]; int rows_per_worker = MATRIX_SIZE / NUM_WORKERS; for (int i = 0; i < NUM_WORKERS; i++) { thread_work[i].a = a; thread_work[i].b = b; thread_work[i].c = c; thread_work[i].start_row = i * rows_per_worker; thread_work[i].end_row = (i == NUM_WORKERS - 1) ? MATRIX_SIZE : (i + 1) * rows_per_worker; pthread_create(&threads[i], NULL, thread_matrix_multiply, &thread_work[i]); } for (int i = 0; i < NUM_WORKERS; i++) { pthread_join(threads[i], NULL); } gettimeofday(&end, NULL); long thread_time = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec); // Process implementation gettimeofday(&start, NULL); for (int i = 0; i < NUM_WORKERS; i++) { pid_t pid = fork(); if (pid == 0) { int start_row = i * rows_per_worker; int end_row = (i == NUM_WORKERS - 1) ? MATRIX_SIZE : (i + 1) * rows_per_worker; process_matrix_multiply(a, b, c, start_row, end_row); exit(0); } } for (int i = 0; i < NUM_WORKERS; i++) { wait(NULL); } gettimeofday(&end, NULL); long process_time = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec); printf("Thread implementation time: %ld microseconds\n", thread_time); printf("Process implementation time: %ld microseconds\n", process_time); // Clean up munmap(a, matrix_bytes); munmap(b, matrix_bytes); munmap(c, matrix_bytes); } int main() { compare_performance(); return 0; }

10. 基准测试

这里有一个简单的基准测试工具,用于比较线程和进程性能:

 

c

代码解读

复制代码

#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> #include <sys/wait.h> #include <sys/time.h> #define NUM_ITERATIONS 1000000 #define NUM_RUNS 10 typedef struct { long thread_times[NUM_RUNS]; long process_times[NUM_RUNS]; } benchmark_results_t; void* thread_work(void* arg) { // Simulate some work double result = 0.0; for (int i = 0; i < NUM_ITERATIONS; i++) { result += i * 1.5; } return NULL; } void process_work() { double result = 0.0; for (int i = 0; i < NUM_ITERATIONS; i++) { result += i * 1.5; } } benchmark_results_t run_benchmarks() { benchmark_results_t results; struct timeval start, end; for (int run = 0; run < NUM_RUNS; run++) { // Thread benchmark gettimeofday(&start, NULL); pthread_t thread; pthread_create(&thread, NULL, thread_work, NULL); pthread_join(thread, NULL); gettimeofday(&end, NULL); results.thread_times[run] = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec); // Process benchmark gettimeofday(&start, NULL); pid_t pid = fork(); if (pid == 0) { process_work(); exit(0); } else { wait(NULL); } gettimeofday(&end, NULL); results.process_times[run] = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec); } return results; } void analyze_results(benchmark_results_t results) { double thread_avg = 0.0, process_avg = 0.0; long thread_min = results.thread_times[0]; long thread_max = results.thread_times[0]; long process_min = results.process_times[0]; long process_max = results.process_times[0]; for (int i = 0; i < NUM_RUNS; i++) { thread_avg += results.thread_times[i]; process_avg += results.process_times[i]; if (results.thread_times[i] < thread_min) thread_min = results.thread_times[i]; if (results.thread_times[i] > thread_max) thread_max = results.thread_times[i]; if (results.process_times[i] < process_min) process_min = results.process_times[i]; if (results.process_times[i] > process_max) process_max = results.process_times[i]; } thread_avg /= NUM_RUNS; process_avg /= NUM_RUNS; printf("Thread Performance:\n"); printf(" Average: %.2f microseconds\n", thread_avg); printf(" Min: %ld microseconds\n", thread_min); printf(" Max: %ld microseconds\n", thread_max); printf("\nProcess Performance:\n"); printf(" Average: %.2f microseconds\n", process_avg); printf(" Min: %ld microseconds\n", process_min); printf(" Max: %ld microseconds\n", process_max); } int main() { printf("Running benchmarks...\n"); benchmark_results_t results = run_benchmarks(); printf("\nBenchmark Results:\n"); analyze_results(results); return 0; }

以下是帮助你可视化线程和进程生命周期及其交互模式的图表:

进程交互模式: 

image.png

线程交互模式:

image.png

12.进一步阅读

  1. Books

    • "Operating System Concepts" by Silberschatz, Galvin, and Gagne
    • "Advanced Programming in the UNIX Environment" by W. Richard Stevens
    • "The Linux Programming Interface" by Michael Kerrisk
  2. Online Resources

13.结论

线程和进程之间的选择取决于各种因素:

  1. 内存使用
  • 由于独立的地址空间,进程具有更高的内存开销
  • 线程共享内存空间,使其更高效地使用内存
  1. 通信开销
  • 进程间通信更复杂,速度更慢
  • 线程共享内存,因此通信速度更快
  1. 隔离和安全性
  • 进程可以提供更好的隔离和安全性
  • 线程更容易受到攻击进而影响整个进程
  1. 开发复杂性
  • 基于进程的程序通常更易于调试
  • 基于线程的程序需要仔细的同步

以下是一个决策辅助函数:

 

c

代码解读

复制代码

typedef enum { REQUIREMENT_ISOLATION, REQUIREMENT_PERFORMANCE, REQUIREMENT_COMMUNICATION, REQUIREMENT_SECURITY } requirement_t; typedef struct { int isolation_weight; int performance_weight; int communication_weight; int security_weight; } requirements_t; const char* suggest_implementation(requirements_t reqs) { int process_score = 0; int thread_score = 0; // Calculate scores based on requirements process_score += reqs.isolation_weight * 9; // Processes excel at isolation process_score += reqs.performance_weight * 5; // Moderate performance process_score += reqs.communication_weight * 3; // Poor for communication process_score += reqs.security_weight * 9; // Excellent security thread_score += reqs.isolation_weight * 3; // Poor isolation thread_score += reqs.performance_weight * 8; // Excellent performance thread_score += reqs.communication_weight * 9; // Excellent communication thread_score += reqs.security_weight * 4; // Moderate security return (process_score > thread_score) ? "Use Processes" : "Use Threads"; } // Example usage: void demonstrate_decision_making() { requirements_t reqs = { .isolation_weight = 8, // High importance .performance_weight = 5, // Medium importance .communication_weight = 3, // Low importance .security_weight = 9 // Critical importance }; printf("Suggestion: %s\n", suggest_implementation(reqs)); }

14.参考资料

  1. IEEE POSIX Standard (IEEE Std 1003.1-2017)
  2. Linux Kernel Documentation (processes and threads)
  3. GNU C Library Manual
  4. "Modern Operating Systems" by Andrew S. Tanenbaum
  5. "Understanding the Linux Kernel" by Daniel P. Bovet and Marco Cesati

15. 最后思考

理解线程和进程之间的差异对于系统设计至关重要。以下是一个快速参考实现,展示了两种方法:

 

c

代码解读

复制代码

#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> #include <sys/wait.h> #include <sys/time.h> #include <string.h> #include <sys/mman.h> #include <fcntl.h> #define NUM_ITEMS 1000 #define SHARED_MEM_NAME "/shared_mem_example" // Requirements structure for decision making typedef struct { int isolation_weight; int performance_weight; int communication_weight; int security_weight; } requirements_t; // Common data structure for both approaches typedef struct { int* data; int start_index; int end_index; } work_data_t; // Common interface for both approaches typedef struct { void (*initialize)(void* processor_data); void (*process_data)(void* processor_data, work_data_t* work); void (*cleanup)(void* processor_data); void* processor_data; } concurrent_processor_t; // Thread-based implementation typedef struct { pthread_t* threads; int num_threads; int* shared_data; pthread_mutex_t mutex; work_data_t* work_units; } thread_processor_t; // Process-based implementation typedef struct { pid_t* processes; int num_processes; int* shared_memory; int shm_fd; work_data_t* work_units; } process_processor_t; // Decision making function const char* suggest_implementation(requirements_t reqs) { int process_score = 0; int thread_score = 0; process_score += reqs.isolation_weight * 9; process_score += reqs.performance_weight * 5; process_score += reqs.communication_weight * 3; process_score += reqs.security_weight * 9; thread_score += reqs.isolation_weight * 3; thread_score += reqs.performance_weight * 8; thread_score += reqs.communication_weight * 9; thread_score += reqs.security_weight * 4; return (process_score > thread_score) ? "Use Processes" : "Use Threads"; } // Thread worker function void* thread_worker(void* arg) { work_data_t* work = (work_data_t*)arg; for (int i = work->start_index; i < work->end_index; i++) { work->data[i] *= 2; // Simple data processing } return NULL; } // Thread implementation functions void thread_initialize(void* processor_data) { thread_processor_t* tp = (thread_processor_t*)processor_data; tp->shared_data = malloc(NUM_ITEMS * sizeof(int)); tp->work_units = malloc(tp->num_threads * sizeof(work_data_t)); // Initialize data for (int i = 0; i < NUM_ITEMS; i++) { tp->shared_data[i] = i; } pthread_mutex_init(&tp->mutex, NULL); } void thread_process_data(void* processor_data, work_data_t* work) { thread_processor_t* tp = (thread_processor_t*)processor_data; int items_per_thread = NUM_ITEMS / tp->num_threads; // Create and start threads for (int i = 0; i < tp->num_threads; i++) { tp->work_units[i].data = tp->shared_data; tp->work_units[i].start_index = i * items_per_thread; tp->work_units[i].end_index = (i == tp->num_threads - 1) ? NUM_ITEMS : (i + 1) * items_per_thread; pthread_create(&tp->threads[i], NULL, thread_worker, &tp->work_units[i]); } // Wait for threads to complete for (int i = 0; i < tp->num_threads; i++) { pthread_join(tp->threads[i], NULL); } } void thread_cleanup(void* processor_data) { thread_processor_t* tp = (thread_processor_t*)processor_data; pthread_mutex_destroy(&tp->mutex); free(tp->shared_data); free(tp->work_units); free(tp->threads); free(tp); } // Process worker function void process_worker(work_data_t* work) { for (int i = work->start_index; i < work->end_index; i++) { work->data[i] *= 2; // Simple data processing } exit(0); } // Process implementation functions void process_initialize(void* processor_data) { process_processor_t* pp = (process_processor_t*)processor_data; // Create shared memory pp->shm_fd = shm_open(SHARED_MEM_NAME, O_CREAT | O_RDWR, 0666); ftruncate(pp->shm_fd, NUM_ITEMS * sizeof(int)); pp->shared_memory = mmap(NULL, NUM_ITEMS * sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, pp->shm_fd, 0); pp->work_units = malloc(pp->num_processes * sizeof(work_data_t)); // Initialize data for (int i = 0; i < NUM_ITEMS; i++) { pp->shared_memory[i] = i; } } void process_process_data(void* processor_data, work_data_t* work) { process_processor_t* pp = (process_processor_t*)processor_data; int items_per_process = NUM_ITEMS / pp->num_processes; // Create and start processes for (int i = 0; i < pp->num_processes; i++) { pp->work_units[i].data = pp->shared_memory; pp->work_units[i].start_index = i * items_per_process; pp->work_units[i].end_index = (i == pp->num_processes - 1) ? NUM_ITEMS : (i + 1) * items_per_process; pid_t pid = fork(); if (pid == 0) { process_worker(&pp->work_units[i]); } pp->processes[i] = pid; } // Wait for processes to complete for (int i = 0; i < pp->num_processes; i++) { waitpid(pp->processes[i], NULL, 0); } } void process_cleanup(void* processor_data) { process_processor_t* pp = (process_processor_t*)processor_data; munmap(pp->shared_memory, NUM_ITEMS * sizeof(int)); shm_unlink(SHARED_MEM_NAME); free(pp->work_units); free(pp->processes); free(pp); } concurrent_processor_t* create_processor(int is_threaded, int num_workers) { concurrent_processor_t* processor = malloc(sizeof(concurrent_processor_t)); if (is_threaded) { thread_processor_t* tp = malloc(sizeof(thread_processor_t)); tp->threads = malloc(num_workers * sizeof(pthread_t)); tp->num_threads = num_workers; processor->initialize = thread_initialize; processor->process_data = thread_process_data; processor->cleanup = thread_cleanup; processor->processor_data = tp; } else { process_processor_t* pp = malloc(sizeof(process_processor_t)); pp->processes = malloc(num_workers * sizeof(pid_t)); pp->num_processes = num_workers; processor->initialize = process_initialize; processor->process_data = process_process_data; processor->cleanup = process_cleanup; processor->processor_data = pp; } return processor; } void print_results(int* data, int size) { printf("First 10 results: "); for (int i = 0; i < 10 && i < size; i++) { printf("%d ", data[i]); } printf("\n"); } int main() { // Choose implementation based on requirements requirements_t reqs = { .isolation_weight = 5, .performance_weight = 8, .communication_weight = 7, .security_weight = 4 }; const char* suggestion = suggest_implementation(reqs); printf("Based on requirements, suggestion: %s\n", suggestion); int use_threads = (strcmp(suggestion, "Use Threads") == 0); concurrent_processor_t* processor = create_processor(use_threads, 4); // Initialize the processor processor->initialize(processor->processor_data); // Process data work_data_t work = {0}; // Dummy work data, actual work units are created inside struct timeval start, end; gettimeofday(&start, NULL); processor->process_data(processor->processor_data, &work); gettimeofday(&end, NULL); long microseconds = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec); // Print results if (use_threads) { thread_processor_t* tp = (thread_processor_t*)processor->processor_data; print_results(tp->shared_data, NUM_ITEMS); } else { process_processor_t* pp = (process_processor_t*)processor->processor_data; print_results(pp->shared_memory, NUM_ITEMS); } printf("Processing time: %ld microseconds\n", microseconds); // Cleanup processor->cleanup(processor->processor_data); free(processor); return 0; }

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值