POSIX 線程提供 pthread_key_t 機制,讓同一進程內不同線程擁有同名但獨立儲存空間的資料。典型應用:線程局部緩衝區、錯誤碼、資料庫連線句柄等。
| 函式 | 用途 |
|---|---|
pthread_key_create(&key, destructor) | 建立鍵,指定銷毀回調 |
pthread_setspecific(key, value) | 設定當前線程該鍵對應的值 |
pthread_getspecific(key) | 取得當前線程該鍵對應的值 |
pthread_key_delete(key) | 刪除鍵(不釋放值記憶體,線程結束時呼叫 destructor) |
#include
#include
#include
#include
struct mydata { int x; char c[4]; };
pthread_key_t datakey;
pthread_t th_a, th_b;
void cleanup(void *ptr) { free(ptr); }
void *thread_a(void *arg) {
struct mydata *d = malloc(sizeof(*d));
d->x = 1; d->c[0] = 'a'; d->c[1] = '\0';
pthread_setspecific(datakey, d);
sleep(1);
struct mydata *gd = pthread_getspecific(datakey);
printf("Thread A: %d %s\n", gd->x, gd->c);
return NULL;
}
void *thread_b(void *arg) {
struct mydata *d = malloc(sizeof(*d));
d->x = 2; d->c[0] = 'b'; d->c[1] = '\0';
pthread_setspecific(datakey, d);
sleep(1);
struct mydata *gd = pthread_getspecific(datakey);
printf("Thread B: %d %s\n", gd->x, gd->c);
return NULL;
}
int main() {
pthread_key_create(&datakey, cleanup);
pthread_create(&th_a, NULL, thread_a, NULL);
pthread_create(&th_b, NULL, thread_b, NULL);
sleep(3);
pthread_join(th_a, NULL);
pthread_join(th_b, NULL);
pthread_key_delete(datakey);
return 0;
}
輸出:
Thread A: 1 a
Thread B: 2 b
雖使用同一 datakey,兩線程存取的是完全獨立的記憶體區塊。
fork + execlp + waitpid利用 execlp 在子進程執行外部命令,父進程 waitpid 回收,構建極簡互動式 Shell。
int execlp(const char *file, const char *arg0, ..., NULL);
// file: 命令名(會搜尋 PATH)
// arg0...argn: argv[0]...argv[n],必須以 NULL 結尾
#include
#include
#include
#include
#include
#define MAXLINE 100
int main() {
char buf[MAXLINE];
pid_t pid;
int status;
printf("##myhaspl~~"); // 提示符
while (fgets(buf, MAXLINE, stdin) != NULL) {
size_t len = strlen(buf);
if (len > 0 && buf[len-1] == '\n') buf[len-1] = '\0'; // 去換行
if ((pid = fork()) < 0) {
perror("fork error");
} else if (pid == 0) { // 子進程
if (strcmp(buf, "Q") == 0) exit(200); // 內建退出命令
execlp(buf, buf, (char*)0);
perror("execlp failed"); // 若返回必失敗
exit(127);
}
// 父進程等待
if (waitpid(pid, &status, 0) < 0) perror("waitpid error");
if (WEXITSTATUS(status) == 200) { printf("退出....\n"); break; }
printf("##myhaspl~~");
}
return 0;
}
##myhaspl~~ls
Makefile shell.c test.txt
##myhaspl~~pwd
/home/user/demo
##myhaspl~~nonexist
execlp failed: No such file or directory
##myhaspl~~Q
退出....
waitpid 進階用法pid_t waitpid(pid_t pid, int *stat_loc, int options);
// pid: >0 特定進程, -1 任一子進程, 0 同進程組
// options: WNOHANG (非阻塞), WUNTRACED (報告停止狀態)
// 宏檢查退出狀態
WIFEXITED(status) // 正常退出
WEXITSTATUS(status) // 取得 exit code
WIFSIGNALED(status) // 訊號終止
WTERMSIG(status) // 終止訊號編號
讀入 → fork → 子進程 execlp → 父進程 waitpid,掌握此模式即可擴展內建命令、管道、重導向等功能。execlp 失敗時務必 exit,避免子進程繼續執行父進程邏輯。