Back to COMP1521 返回 COMP1521

Pthread Deep Dive Tutorial Pthread 深度教程

Complete guide to multithreading in C - from basics to exam mastery C语言多线程完整指南 - 从基础到考试精通

4 Learning Modules 4个学习模块 3 Complete Examples 3个完整示例 Interactive Simulator 交互式模拟器

📦 Visual Guide - Understanding Pthread Basics 📦 超简单图解 - 一看就懂的Pthread

Concept 1: What is arg? 概念1:arg(参数)是什么?

Real-world analogy: Think of a delivery service 生活例子:外卖配送

Boss (main function)          →         Delivery Person (thread function)
Prepares order (data)                    Receives order (arg)
    ↓                                        ↓
"Address: 123 Main St"                  "This package is the order"
"Food: Pizza"                           "Let me open it..."
"Phone: 123456"老板(主函数)          →         送餐员(线程函数)
准备订单(数据)                 接收订单(arg)
    ↓                              ↓
"地址:XX路123号"              "这个包裹里是订单"
"食物:披萨"                  "打开看看..."
"电话:123456"
Understanding arg - Code Example 理解 arg - 代码示例
// Boss prepares the order (main function)
struct thread_data order = {
    .address = "123 Main St",
    .food = "Pizza",
    .phone = "123456"
};

// Delivery person receives the order (thread function)
void *delivery(void *arg) {  // ← arg is the "package"
    // Open the package to see what's inside...
}

✅ Summary: arg = the "package" passed to the thread ✅ 总结:arg = 传给线程的"包裹"

Concept 2: (struct thread_data *)arg - Opening the Package 概念2:(struct thread_data *)arg - 拆包裹

Real-world analogy: Receiving a package 生活例子:收快递

You receive a package (arg)
    ↓
Package label: "Generic Package" (void*)
    ↓
But you ordered a "Book" (struct thread_data)
    ↓
Open it: It IS a book!
    ↓
(struct thread_data *)arg  ← Telling the system: "This is a book!"你收到一个包裹(arg)
    ↓
包裹上写着:"通用包裹"(void*)
    ↓
但你订的是"书籍"(struct thread_data)
    ↓
拆开看看:确实是书!
    ↓
(struct thread_data *)arg  ← 告诉系统:"这是书!"
Type Casting Step-by-Step 类型转换 - 分步解释
void *worker(void *arg) {
    // Step 1: Receive the package
    void *arg  // Generic box

    // Step 2: Open the package (type casting)
    (struct thread_data *)arg  // "Open it! This is a task sheet!"

    // Step 3: Give it a name for easy use
    struct thread_data *data = (struct thread_data *)arg;

    // Step 4: Now you can use it!
    data->thread_id  // Read the task sheet's ID
}

✅ Summary: Type casting = telling the system "what's in the package" ✅ 总结:类型转换 = 告诉系统"包裹里是什么"

Concept 3: FILE *fp - File Pointer 概念3:FILE *fp - 文件指针

Real-world analogy: Library card 生活例子:图书馆借书证

Library (file)              →          Your library card (FILE *fp)
Many books                          ←     Use card to borrow books
                                             |
                                             ↓
                                    Can only operate through the card
                                    (Cannot directly touch the file)图书馆(文件)          →          你的借书证(FILE *fp)
很多书                        ←     用借书证借书
                                       |
                                       ↓
                                  只能通过借书证操作
                                  (不能直接操作文件)
FILE Pointer Usage 文件指针用法
// FILE is like the "library card" type
// *fp is your library card

FILE *fp;  // I have a "file library card"

// With this card you can:
// - Open file (borrow book)
// - Read content (read book)
// - Close file (return book)

✅ Summary: FILE *fp = the "remote control" for files ✅ 总结:FILE *fp = 文件的"遥控器"

Concept 4: fopen() - Opening Files 概念4:fopen() - 打开文件

Real-world analogy: Opening a door 生活例子:开门

fopen() Modes fopen() 模式
// Opening a file
FILE *fp = fopen("data.txt", "r");
//         ^^^^^^^^^^^^^^^^^^^^^^
//         Open "data.txt", mode is "read"
//         ^^^
//         Returns the "key" (file pointer)

if (fp == NULL) {
    // No key! Door won't open!
    printf("Cannot open file!\n");
} else {
    // Got the key! Can enter now!
    printf("File opened successfully!\n");
}

// Different modes (like different keys)
fopen("file.txt", "r");   // "Read" key - can only view, not modify
fopen("file.txt", "w");   // "Write" key - can write, clears old content
fopen("file.txt", "a");   // "Append" key - adds at the end
fopen("file.txt", "r+");  // "Read/Write" key - can view and modify

✅ Summary: fopen() = open file, gives you "remote control" ✅ 总结:fopen() = 打开文件,给你"遥控器"

Concept 5: -> Operator 概念5:-> 操作符

Real-world analogy: Remote control for TV 生活例子:遥控器操作电视

. vs -> Comparison . vs -> 对比
// Method 1: Direct access (variable)
struct thread_data info;    // TV is in your hands
info.thread_id = 0;         // Press button directly (use .)

// Method 2: Use remote control (pointer)
struct thread_data *data = &info;  // You have the remote
data->thread_id = 0;                // Use remote to press button (use ->)

// Comparison table:
// ╔═══════════════════════╦═══════╦═══════════════════╗
// ║ Situation             ║ Use   ║ Example           ║
// ╠═══════════════════════╬═══════╬═══════════════════╣
// ║ Variable (TV in hand) ║  .    ║ info.thread_id    ║
// ║ Pointer (have remote) ║  ->   ║ data->thread_id   ║
// ╚═══════════════════════╩═══════╩═══════════════════╝

✅ Summary: -> = "remote access" to struct members through pointer ✅ 总结:-> = 通过指针"遥控"访问结构体成员

🎬 Complete Flow: Putting It All Together 🎬 完整流程:所有概念串联

Step 1: Main function prepares "task sheet"
    ↓
struct thread_data task;
task.thread_id = 0;
task.filename = "data.txt";
    ↓
Step 2: Create thread, pass "task sheet address"
    ↓
pthread_create(..., &task);
    ↓
        Passed to thread function
    ↓
Step 3: Thread function receives "package" (arg)
    ↓
void *worker(void *arg)  // arg is the "package"
    ↓
Step 4: Open package (type casting)
    ↓
struct thread_data *data = (struct thread_data *)arg;
    ↓
Step 5: Use data-> to access task sheet contents
    ↓
printf("Filename: %s\n", data->filename);
    ↓
Step 6: Open file
    ↓
FILE *fp = fopen(data->filename, "r");
    ↓
Step 7: Use file pointer to operate on file
    ↓
fseek(fp, ...);
fgets(line, 11, fp);
    ↓
Step 8: Close file
    ↓
fclose(fp);步骤1:主函数准备"任务单"
    ↓
struct thread_data task;
task.thread_id = 0;
task.filename = "data.txt";
    ↓
步骤2:创建线程,传递"任务单的地址"
    ↓
pthread_create(..., &task);
    ↓
        传给线程函数
    ↓
步骤3:线程函数接收"包裹"(arg)
    ↓
void *worker(void *arg)  // arg 是"包裹"
    ↓
步骤4:拆包裹(类型转换)
    ↓
struct thread_data *data = (struct thread_data *)arg;
    ↓
步骤5:用 data-> 访问任务单内容
    ↓
printf("文件名:%s\n", data->filename);
    ↓
步骤6:打开文件
    ↓
FILE *fp = fopen(data->filename, "r");
    ↓
步骤7:用文件指针操作文件
    ↓
fseek(fp, ...);
fgets(line, 11, fp);
    ↓
步骤8:关闭文件
    ↓
fclose(fp);

🎯 Quick Memory Cards 🎯 快速记忆卡

Memory Card 1: arg 口诀1:arg

arg = package
Passed to you, must openarg = 包裹
传给你,要拆开

Memory Card 2: Type Casting 口诀2:类型转换

(void*) → (struct thread_data*)
Generic box → Task sheet box(void*) → (struct thread_data*)
通用盒 → 任务单盒

Memory Card 3: FILE *fp 口诀3:FILE *fp

FILE *fp = file remote control
fopen() = turn on, gives you remote
fclose() = turn off, return remoteFILE *fp = 文件遥控器
fopen() = 开机,给你遥控器
fclose() = 关机,还遥控器

Memory Card 4: -> 口诀4:->

Pointer uses ->
Variable uses .
Remember this!指针用 ->
变量用 .
记住这个!

✅ Self-Test Questions ✅ 自我测试

Fill in the blanks 填空题
void *worker(void *arg) {
    // Q1: Convert arg to what type?
    struct thread_data *data = (______)arg;

    // Q2: Use what operator to access struct member?
    printf("%s\n", data______filename);

    // Q3: What function opens a file?
    FILE *fp = ______(data->filename, "r");
}

// Answers:
// 1. struct thread_data *
// 2. ->
// 3. fopen

📚 Core Concepts - Pthread Fundamentals in Detail 📚 基础概念详解 - Pthread核心原理

🔧 pthread_create() 🔧 创建线程

Creates a new thread and starts execution 创建新线程并开始执行

pthread_t thread_id;
pthread_create(
    &thread_id,        // Thread ID
    NULL,              // Attributes
    worker_function,   // Function to run
    &data              // Argument to pass
);

⏳ pthread_join() ⏳ 等待线程

Waits for thread to complete and gets return value 等待线程完成并获取返回值

void *return_value;
pthread_join(
    thread_id,          // Thread to wait for
    &return_value       // Pointer to store return
);

🔒 pthread_mutex_lock() 🔒 互斥锁

Protects shared data from race conditions 保护共享数据,避免竞态条件

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_lock(&lock);
// Critical section
pthread_mutex_unlock(&lock);

⚛️ Atomic Operations ⚛️ 原子操作

Lock-free operations for simple data 简单数据的无锁操作

#include 

atomic_int counter = 0;
atomic_fetch_add(&counter, 1);
int value = atomic_load(&counter);

⚠️ Common Mistakes to Avoid ⚠️ 常见错误(千万别犯!)

❌ Mistake 1: Returning local variable address ❌ 错误1:返回局部变量地址

❌ WRONG: ❌ 错误:

void *worker(void *arg) {
    int count = 10;
    return &count;  // ❌ count disappears!
}

✅ CORRECT: ✅ 正确:

void *worker(void *arg) {
    int *count = malloc(sizeof(int));
    *count = 10;
    return count;  // ✅ malloc memory persists
}

❌ Mistake 2: Forgetting to free memory ❌ 错误2:忘记释放内存

❌ WRONG: ❌ 错误:

pthread_join(thread, (void**)&result);
// Forgot free(result) - memory leak!

✅ CORRECT: ✅ 正确:

pthread_join(thread, (void**)&result);
total += *result;
free(result);  // ✅ Always free!

❌ Mistake 3: Race condition without locks ❌ 错误3:忘记用锁保护共享数据

❌ WRONG: ❌ 错误:

void *worker(void *arg) {
    total_size += size;  // ❌ Race condition!
}

✅ CORRECT: ✅ 正确:

void *worker(void *arg) {
    pthread_mutex_lock(&lock);
    total_size += size;  // ✅ Protected!
    pthread_mutex_unlock(&lock);
}

💻 Complete Solutions - Past Exam Questions 💻 完整题解 - 历年考试真题

Example 1: 22T3 Final Q9 - Parallel Expression Evaluation 示例 1:22T3 Final Q9 - 并行表达式计算

📋 Problem Description: 📋 题目描述:

  • File has 2880 lines of mathematical expressions (e.g., "1+2*3-4/5")
  • Original program uses 1 thread - too slow
  • Convert to use 5 threads for 5x speedup
  • Each thread processes different part of file
  • 文件有2880行数学表达式(如"1+2*3-4/5")
  • 原程序用1个线程,太慢了
  • 改成5个线程,快5倍
  • 每个线程处理文件的不同部分

Code 代码

// Will show highlighted code during simulation

Execution Output 执行输出

Click "Run Simulation" to start... 点击"运行模拟"开始...
22T3 Q9 - Complete Solution 22T3 Q9 - 完整解答
#include 
#include 
#include 

// Step 1: Define "task sheet" structure
struct thread_data {
    int thread_id;        // Thread number: 0, 1, 2, 3, 4
    int start_line;       // Starting line
    int end_line;         // Ending line
    char *filename;       // File name
};

// Step 2: Thread function (what each thread does)
void *worker_thread(void *arg) {
    // 1. Get the "task sheet"
    struct thread_data *data = (struct thread_data *)arg;

    printf("Thread %d starts: lines %d to %d\n",
           data->thread_id, data->start_line, data->end_line);

    // 2. Open file (each thread opens separately to avoid conflicts)
    FILE *fp = fopen(data->filename, "r");
    if (fp == NULL) {
        printf("Thread %d: Cannot open file\n", data->thread_id);
        return NULL;
    }

    // 3. Jump to my starting position
    // Each line is 10 chars, so: start byte = line_number × 10
    fseek(fp, data->start_line * 10, SEEK_SET);

    // 4. Initialize counter
    int count = 0;
    char line[11];  // 10 chars + '\0'

    // 5. Read and process my lines
    for (int i = data->start_line; i <= data->end_line; i++) {
        if (fgets(line, 11, fp) == NULL) {
            break;
        }
        // TODO: Call evaluate_expression(line) and check if == 10
        // count += (evaluate_expression(line) == 10);
    }

    // 6. Close file
    fclose(fp);

    // 7. Return result (must use malloc, local variable disappears!)
    int *result = malloc(sizeof(int));
    *result = count;

    printf("Thread %d complete: found %d expressions\n",
           data->thread_id, count);

    return result;
}

// Step 3: Main function (boss assigns tasks)
int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Usage: %s \n", argv[0]);
        return 1;
    }

    char *filename = argv[1];
    int total_lines = 2880;
    int num_threads = 5;
    int lines_per_thread = total_lines / num_threads;

    // Create 5 "task sheets" and 5 threads
    struct thread_data thread_args[5];
    pthread_t threads[5];

    // Assign work to each thread
    for (int i = 0; i < 5; i++) {
        thread_args[i].thread_id = i;
        thread_args[i].start_line = i * lines_per_thread;
        thread_args[i].end_line = (i + 1) * lines_per_thread - 1;
        thread_args[i].filename = filename;

        // Last thread handles remaining lines
        if (i == 4) {
            thread_args[i].end_line = total_lines - 1;
        }

        // Create thread, give it "task sheet"
        pthread_create(&threads[i], NULL, worker_thread, &thread_args[i]);
    }

    // Wait for all threads to complete, collect results
    int total_count = 0;
    for (int i = 0; i < 5; i++) {
        int *result;
        pthread_join(threads[i], (void **)&result);

        if (result != NULL) {
            total_count += *result;
            free(result);  // Don't forget to free!
        }
    }

    printf("\n=== Final Result ===\n");
    printf("Found %d expressions equal to 10\n", total_count);

    return 0;
}

/*
 * Key Points:
 *
 * 1. Why not use global variables?
 *    - 5 threads modifying same global variable → conflict (race condition)
 *    - Each thread returns own result, main thread adds them up
 *
 * 2. Why use malloc for return value?
 *    - pthread_join needs pointer
 *    - Returning local variable address → variable disappears after function
 *    - malloc allocates on heap → persists
 *
 * 3. Why each thread opens file separately?
 *    - Multiple threads sharing one file pointer → interfere with each other
 *    - Each thread uses fseek to jump to own position
 *
 * 4. How to divide work evenly?
 *    - 2880 ÷ 5 = 576 lines/thread
 *    - Thread 0: 0-575
 *    - Thread 1: 576-1151
 *    - ...and so on
 */

Example 2: 22T2 Final Q9 - File Monitoring (Mutex Version) 示例 2:22T2 Final Q9 - 文件监控(互斥锁版本)

📋 Problem Description: 📋 题目描述:

  • Monitor multiple files' sizes with separate threads
  • If total size exceeds quota → print warning
  • If later drops below → print resolved message
  • Must use mutex or atomic operations
  • 用多个线程监控多个文件大小
  • 如果总大小超过配额 → 打印警告
  • 如果后来变小了 → 打印解决消息
  • 必须用互斥锁或原子操作
22T2 Q9 - Mutex Solution 22T2 Q9 - 互斥锁解法
#include 
#include 
#include 

#define QUOTA 10
#define FILE_NOT_FOUND -1
#define QUOTA_EXCEEDED_MESSAGE "Quota exceeded!"
#define QUOTA_RESOLVED_MESSAGE "Quota resolved!"

// Shared data (needs protection)
int total_size = 0;
int warning_printed = 0;

// Mutex lock (like a key)
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

// Thread function: monitor one file
void *watch_file(void *arg) {
    char *filename = (char *)arg;

    printf("Thread starts monitoring: %s\n", filename);

    // Keep monitoring until file is deleted
    while (1) {
        int size = file_size(filename);

        if (size == FILE_NOT_FOUND) {
            printf("File %s deleted, thread exits\n", filename);
            break;
        }

        // ========== Critical Section: Use lock to protect shared data ==========
        // 🔒 Acquire lock (only one thread can enter)
        pthread_mutex_lock(&lock);

        // Update total size
        total_size += size;

        // Check if exceeds quota
        if (total_size > QUOTA && !warning_printed) {
            printf("%s\n", QUOTA_EXCEEDED_MESSAGE);
            warning_printed = 1;
        } else if (total_size <= QUOTA && warning_printed) {
            printf("%s\n", QUOTA_RESOLVED_MESSAGE);
            warning_printed = 0;
        }

        // 🔓 Release lock (let others use)
        pthread_mutex_unlock(&lock);

        // Wait before checking again
        usleep(100000);  // 0.1 second
    }

    return NULL;
}

int main(void) {
    char *files[] = {"file1", "file2", "file3"};
    int num_files = 3;
    pthread_t threads[num_files];

    // Create monitoring thread for each file
    for (int i = 0; i < num_files; i++) {
        pthread_create(&threads[i], NULL, watch_file, files[i]);
    }

    // Wait for all threads to complete
    for (int i = 0; i < num_files; i++) {
        pthread_join(threads[i], NULL);
    }

    return 0;
}

/*
 * Key Concepts:
 *
 * 1. What is a race condition?
 *    Imagine you and friend both putting money in same piggy bank:
 *    - You see $10 in piggy bank
 *    - Friend also sees $10 (not updated yet)
 *    - You add $5, write back $15
 *    - Friend adds $3, writes back $13 (overwrites yours!)
 *    - Should be $18, but only $13
 *
 * 2. How does mutex work?
 *    - Like a key, only one person can hold it
 *    - Person with key can modify data
 *    - After modification, return key for next person
 *    - This prevents conflicts
 *
 * 3. Why need warning_printed flag?
 *    - Avoid printing same message repeatedly
 *    - Only print when state changes
 *
 * 4. Why use usleep?
 *    - Let thread rest, don't check too frequently
 *    - Reduces CPU usage
 *    - Also reduces file system load
 */

Example 3: 22T2 Final Q9 - File Monitoring (Atomic Version) 示例 3:22T2 Final Q9 - 文件监控(原子操作版本)

🆚 Mutex vs Atomic Operations 🆚 互斥锁 vs 原子操作

Atomic Operations: 原子操作:
  • ✅ Faster (no waiting for locks)
  • ✅ Can't deadlock (no locks)
  • ❌ Only for simple operations
  • ❌ Slightly more complex code
  • ✅ 更快(不需要等待锁)
  • ✅ 不会死锁(没有锁)
  • ❌ 只能用于简单操作
  • ❌ 代码稍微复杂
Mutex: 互斥锁:
  • ✅ Simple to understand
  • ✅ Can protect complex code
  • ❌ Need to wait (slower)
  • ❌ Can deadlock if forget unlock
  • ✅ 简单易懂
  • ✅ 可保护复杂代码
  • ❌ 需要等待(可能慢)
  • ❌ 忘记解锁会死锁
22T2 Q9 - Atomic Solution 22T2 Q9 - 原子操作解法
#include 
#include 
#include 
#include 

#define QUOTA 10
#define FILE_NOT_FOUND -1
#define QUOTA_EXCEEDED_MESSAGE "Quota exceeded!"
#define QUOTA_RESOLVED_MESSAGE "Quota resolved!"

// Shared data (using atomic types)
atomic_int total_size = 0;
atomic_int warning_printed = 0;

void *watch_file(void *arg) {
    char *filename = (char *)arg;

    while (1) {
        int size = file_size(filename);

        if (size == FILE_NOT_FOUND) {
            break;
        }

        // ========== Atomic operations: Safe without locks ==========
        // Atomic operation: safely add to total
        atomic_fetch_add(&total_size, size);

        // Read current values
        int current_total = atomic_load(&total_size);
        int warned = atomic_load(&warning_printed);

        // Check quota
        if (current_total > QUOTA && !warned) {
            // Atomic: set warning flag (if not already set)
            int expected = 0;
            if (atomic_compare_exchange_strong(&warning_printed, &expected, 1)) {
                // Only first thread reaching here prints
                printf("%s\n", QUOTA_EXCEEDED_MESSAGE);
            }
        } else if (current_total <= QUOTA && warned) {
            // Atomic: clear warning flag
            int expected = 1;
            if (atomic_compare_exchange_strong(&warning_printed, &expected, 0)) {
                printf("%s\n", QUOTA_RESOLVED_MESSAGE);
            }
        }

        usleep(100000);
    }

    return NULL;
}

int main(void) {
    char *files[] = {"file1", "file2", "file3"};
    int num_files = 3;
    pthread_t threads[num_files];

    for (int i = 0; i < num_files; i++) {
        pthread_create(&threads[i], NULL, watch_file, files[i]);
    }

    for (int i = 0; i < num_files; i++) {
        pthread_join(threads[i], NULL);
    }

    return 0;
}

⚡ Quick Review - Exam Prep Cheat Sheet ⚡ 快速复习 - 考试速记卡

📋 Core Functions (Must Remember) 📋 核心函数(必须记住)

1. Create Thread 1. 创建线程

pthread_create(&thread_id, NULL,
               thread_function,
               argument_to_pass);
  • thread_id: Thread's "ID card"线程的"身份证"
  • NULL: Thread attributes (usually NULL for exams)线程属性(考试通常用NULL)
  • thread_function: Function thread will execute线程要执行的函数
  • argument: Data passed to thread (usually struct pointer)传给线程的数据(通常是结构体指针)

2. Wait for Thread 2. 等待线程完成

pthread_join(thread_id, &return_value_ptr);
  • thread_id: Thread to wait for要等待的线程
  • return_value_ptr: Receives thread's return value用来接收线程的返回值

3. Mutex Lock (22T2 Q9 needs this) 3. Mutex 锁(22T2 Q9需要)

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_lock(&lock);
// ... protected critical code ...
pthread_mutex_unlock(&lock);

🎓 Memory Mnemonics 🎓 记忆口诀

  1. Create thread:创建线程: pthread_create = assign task给任务
  2. Wait complete:等待完成: pthread_join = collect result收结果
  3. Pass data:数据传递: Use struct, not global variables 用结构体,不用全局变量
  4. Return result:返回结果: Use malloc, remember free malloc,记得 free
  5. Protect data:保护数据: Multiple threads modifying same data → use lock 多线程改同一个数据 → 用锁

🎯 Two Common Exam Patterns 🎯 两种常见题型模板

Pattern 1: 22T3 Q9 (Simple - No locks) 题型1:22T3 Q9(简单 - 不用锁)

  • Each thread processes independent file section每个线程处理独立文件部分
  • No shared data → no locks needed没有共享数据 → 不需要锁
  • Each thread returns result, main adds up各线程返回结果,主函数加总
  • Use fseek() to jump to positionfseek() 跳到位置
// Key code snippet
fseek(fp, start_line * 10, SEEK_SET);
for (int i = start; i <= end; i++) {
    fgets(line, 11, fp);
    // process...
}

Pattern 2: 22T2 Q9 (Hard - Needs locks) 题型2:22T2 Q9(困难 - 需要锁)

  • Multiple threads modify shared variable多个线程修改共享变量
  • Must use mutex OR atomic operations必须用互斥锁或原子操作
  • Continuous monitoring in while(1) loopwhile(1) 持续监控
  • Use usleep() to avoid busy-waitingusleep() 避免忙等待
// Key code snippet
pthread_mutex_lock(&lock);
total_size += size;
if (total_size > QUOTA && !warned) {
    printf("Warning!\n");
    warned = 1;
}
pthread_mutex_unlock(&lock);

🧪 Pre-Exam Checklist 🧪 考试前最后检查

  • Remember pthread_create and pthread_join syntax记住 pthread_createpthread_join 语法
  • Know how to pass data with struct知道如何用结构体传递数据
  • Know how to return results with malloc知道如何用 malloc 返回结果
  • Know when to use mutex知道什么时候用 mutex
  • Know how to use fseek to jump to position知道如何用 fseek 跳到文件位置
  • Remember to check boundaries (array, file end)记得检查边界(数组越界、文件结束)
  • Always free() after pthread_join()记得在 pthread_join()free()
  • Each thread opens file separately每个线程自己打开文件

💡 Universal Solution Steps 💡 通用解题步骤

  1. Read question:读题: Understand requirements理解题目要求
  2. Design data structure:设计数据结构: Define "task sheet" struct定义"任务纸"结构
  3. Write thread function:写线程函数: What does each thread do每个线程做什么
  4. Write main function:写主函数: Create threads, assign tasks创建线程,分配任务
  5. Test:测试: Test with small data用小数据测试
  6. Check:检查: Boundary cases, memory leaks边界情况、内存泄漏