首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C 指標原理(88):線程專屬數據與模擬 Shell 實作

     編輯:關於C

一、POSIX 線程專屬數據(Thread-Specific Data)

在多線程環境下,有時需要讓每條線程擁有獨立的資料副本。POSIX 提供 pthread_key_t 機制:同一個鍵在不同線程中可指向不同的記憶體區塊。

核心 API

  • pthread_key_create(&key, destructor):建立鍵,指定銷毀回調。
  • pthread_setspecific(key, value):設定當前線程該鍵對應的值。
  • pthread_getspecific(key):取得當前線程該鍵的值。
  • pthread_key_delete(key):刪除鍵(不釋放值記憶體,線程結束時由 destructor 清理)。

範例程式碼

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

struct mydata { int x; char c[4]; };
pthread_key_t datakey;

void *cleanup_mydata(void *ptr) { free((struct mydata*)ptr); }

void *anum1(void *arg) {
    struct mydata *mdata = malloc(sizeof(struct mydata));
    mdata->x = 1; mdata->c[0] = 'a'; mdata->c[1] = '\0';
    pthread_setspecific(datakey, mdata);
    sleep(1);
    struct mydata *mmdata = pthread_getspecific(datakey);
    printf("-%d-%s\n", mmdata->x, mmdata->c);
    return NULL;
}

void *bnum2(void *arg) {
    struct mydata *mdata = malloc(sizeof(struct mydata));
    mdata->x = 2; mdata->c[0] = 'b'; mdata->c[1] = '\0';
    pthread_setspecific(datakey, mdata);
    sleep(1);
    struct mydata *mmdata = pthread_getspecific(datakey);
    printf("-%d-%s\n", mmdata->x, mmdata->c);
    return NULL;
}

int main() {
    pthread_key_create(&datakey, cleanup_mydata);
    pthread_t ta, tb;
    pthread_create(&ta, NULL, anum1, NULL);
    pthread_create(&tb, NULL, bnum2, NULL);
    sleep(3);
    pthread_join(ta, NULL); pthread_join(tb, NULL);
    pthread_key_delete(datakey);
    return 0;
}

輸出顯示兩線程各自擁有獨立的 mydata 實例,互不干擾。

二、模擬 Shell:execlp + waitpid

利用 fork() 建立子進程,子進程呼叫 execlp() 執行使用者輸入的指令,父進程以 waitpid() 等待子進程結束並取得退出碼。

關鍵函數簽名

int execlp(const char *file, const char *arg0, ..., NULL);
pid_t waitpid(pid_t pid, int *stat_loc, int options);

完整模擬 Shell 程式碼

#include <stdio.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

#define MAXLINE 100

int main() {
    int pid, status, len;
    char buf[MAXLINE];
    printf("\n##myhaspl~~");
    while (fgets(buf, MAXLINE, stdin)) {
        len = strlen(buf) - 1;
        if (buf[len] == '\n') buf[len] = 0;

        pid = fork();
        if (pid < 0) { perror("fork"); continue; }
        else if (pid == 0) { // 子進程
            if (buf[0] == 'Q' && strlen(buf) == 1) exit(200);
            if (execlp(buf, buf, (char*)0) == -1) {
                printf("不能執行:%s\n", buf); exit(127);
            }
        }
        // 父進程
        if (waitpid(pid, &status, 0) < 0) perror("waitpid");
        if (WEXITSTATUS(status) == 200) { printf("退出....\n"); break; }
        printf("\n##myhaspl~~");
    }
    return 0;
}

執行示範

##myhaspl~~ls
...檔案列表...
##myhaspl~~xx
不能執行:xx
##myhaspl~~Q
退出....

waitpid 參數詳解

參數說明
pid-1: 任一子進程; >0: 指定 PID; 0: 同進程組; <-1: 進程組 ID 絕對值
stat_loc儲存退出狀態,配合 WIFEXITED、WEXITSTATUS 等巨集解析
optionsWNOHANG 非阻塞; WUNTRACED 報告已停止子進程

總結

  • 線程專屬數據解決多線程全域變數衝突,配合 destructor 自動釋放資源。
  • execlp 在 PATH 中尋找可執行檔,適合實作命令列解析器。
  • waitpid 提供靈活的子進程狀態回收機制,是 Shell 父進程的核心。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved