執行緒是行程內的輕量級執行單元,共享程式碼區、資料區、檔案描述符,建立/切換成本遠低於行程。本文介紹 POSIX 執行緒庫 (pthread.h) 核心 API:pthread_create、pthread_exit、pthread_join,並以「多執行緒並行複製目前目錄下所有檔案,副檔名改為 .bak」為完整實戰範例,展示執行緒參數傳遞、錯誤處理、資源釋放、主執行緒等待回收流程。
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);
// thread: 輸出建立的執行緒 ID
// attr: 屬性 (NULL 表預設)
// start_routine: 執行緒入口函式,回傳 void*
// arg: 傳遞給入口函式的單一參數
void pthread_exit(void *retval); // 執行緒結束,傳回 retval
int pthread_join(pthread_t thread, void **retval); // 等待指定執行緒結束,取得 retval
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUFFER 512
struct copy_file { int infile; int outfile; };
void *copy(void *arg) {
struct copy_file *file = (struct copy_file *)arg;
int infile = file->infile, outfile = file->outfile;
int bytes_read, bytes_write, *bytes_copy_p;
char buffer[BUFFER], *buffer_p;
if ((bytes_copy_p = malloc(sizeof(int))) == NULL) pthread_exit(NULL);
*bytes_copy_p = 0;
while ((bytes_read = read(infile, buffer, BUFFER)) > 0) {
buffer_p = buffer;
while (bytes_read > 0) {
bytes_write = write(outfile, buffer_p, bytes_read);
if (bytes_write <= 0) break;
buffer_p += bytes_write;
bytes_read -= bytes_write;
}
*bytes_copy_p += bytes_write;
}
close(infile); close(outfile);
pthread_exit(bytes_copy_p);
}
int main(int argc, char **argv) {
struct dirent **namelist;
int num = scandir(".", &namelist, NULL, alphasort);
if (num < 0) { perror("scandir"); exit(1); }
pthread_t *threads = malloc(num * sizeof(pthread_t));
struct copy_file *files = malloc(num * sizeof(struct copy_file));
for (int i = 0; i < num; i++) {
if (namelist[i]->d_type != DT_REG) continue; // 僅處理一般檔案
char src[BUFFER], dst[BUFFER];
snprintf(src, BUFFER, "%s", namelist[i]->d_name);
snprintf(dst, BUFFER, "%s.bak", namelist[i]->d_name);
files[i].infile = open(src, O_RDONLY);
files[i].outfile = open(dst, O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (files[i].infile < 0 || files[i].outfile < 0) continue;
pthread_create(&threads[i], NULL, copy, &files[i]);
}
// 等待所有執行緒結束
for (int i = 0; i < num; i++) {
void *ret;
pthread_join(threads[i], &ret);
if (ret) { printf("Copied %d bytes\n", *(int*)ret); free(ret); }
}
free(threads); free(files);
// 釋放 scandir 記憶體
for (int i = 0; i < num; i++) free(namelist[i]);
free(namelist);
return 0;
}
copy_file 封裝檔案描述符,避免多參數麻煩。bytes_copy_p 必須 malloc,由主執行緒 pthread_join 取得後 free。read/write 遇 EINTR 需重試;write 可能部分寫入需迴圈處理。pthread_join 否則產生殭屍執行緒洩漏資源。gcc -o mtcopy mtcopy.c -lpthread
./mtcopy
掌握 pthread 基礎,即可進入高併發、多核心程式設計的大門。