2016-10-27 158 views
3

我有一些嵌入式操作系統功能,我需要在Linux機器上模擬。我被指示採用的方法是將嵌入式操作系統函數重載並將其包裝在POSIX線程中,以便Linux機器可以在單元測試期間處理嵌入式OS函數。功能指針typedef在c

的嵌入式操作系統函數來創建一個新的線程是: OSCreateTask(OStypeTFP functionPointer, OSTypeTcbP taskId, OStypePrio priority)

我需要轉換的是OStypeTFP型成空函數指針pthread_create預計:(void * (*)(void *)就是編譯器告訴我這是期待)

我希望創建一個我可以使用它像一個typedef:

typedef void (*OStypeTFP)(void); 

// Function to run task/thread in 
void taskFunction(void) { while(1); } 

// Overloaded Embedded OS function 
void OSCreateTask(OStypeTFP tFP, OStypeTcbP tcbP, OStypePrio prio) 
{ 
    pthread_attr_t threadAttrs; 
    pthread_t thread; 

    pthread_attr_init(&threadAttributes); 
    pthread_create(&thread, &threadAttributes, &tFP, NULL); 
} 

// Creates a task that runs in taskFunction 
OSCreateTask (taskFunction, id, prio); 

但編譯器抱怨functionPointer類型void (**)(void)當pthread_create期望void * (*)(void *)

我需要改變我的typedef莫名其妙,還是我需要做一些類型轉換?都?

+0

功能必須採取一個'無效*'參數和返回'無效*' – imreal

+0

你需要閱讀更多關於['pthread_create'](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_create.html)以及一般可能的線程。以及指向函數和函數的指針會衰減指針,以及操作符用指針變量的地址。 –

+0

要「重載」一個函數(名稱),就是提供具有相同名稱但參數類型不同的不同函數。 C不支持。 –

回答

5

你需要一個適配器功能:

typedef void (*OStypeTFP)(void); 

// Function to run task/thread in 
void taskFunction(void) { while(1); } 

void *trampoline(void *arg) 
{ 
    OStypeTFP task = (OStypeTFP)arg; 
    task(); 
    return NULL; 
}  

// Overloaded Embedded OS function 
void OSCreateTask(OStypeTFP tFP, OStypeTcbP tcbP, OStypePrio prio) 
{ 
    pthread_attr_t threadAttrs; 
    pthread_t thread; 

    pthread_attr_init(&threadAttrs); 
    pthread_create(&thread, &threadAttrs, trampoline, tFP); 
} 

// Creates a task that runs in taskFunction 
OSCreateTask (taskFunction, id, prio); 

當然是安全只有當您的系統允許從void *類型轉換函數指針。但是因爲我們在POSIX環境 - 它應該沒問題。

+0

@BjornA。我的錯。謝謝! – Sergio

+0

啊哈!我之前曾嘗試過類似的方法,但我嘗試調用arg()而不是創建新的任務變量,然後調用task()。謝謝! – cjameston

+0

@ 2501的確,C函數和對象指針之間並不需要_require_轉換來工作,但它也沒有_forbid_。而指定'pthread_ *'API的POSIX *要求在函數指針和void *(特別是)之間進行轉換。因此,只要沒有任何需要傳遞給墊片的附加數據,這個答案就沒有問題。由於OP對他們正在模擬的嵌入式操作系統很籠統,我們無法知道他們是否需要額外的數據。 – zwol

3

如果我理解正確,嵌入式操作系統上的線程程序的簽名是void thread_proc(void)。另一方面,對於POSIX線程,它是void *thread_proc(void *)

您不能用cast和typedefs來區分這種差異:您需要安排適當的返回值。你需要一個墊片功能:

typedef void (*OStypeTFP)(void); 
struct emu_OSCreateTask_thread_start_data 
{ 
    OStypeTFP real_thread_proc; 
    // possibly other stuff 
}; 

void *emu_OSCreateTask_shim_thread_proc (void *xctx) 
{ 
    struct emu_OSCreateTask_thread_start_data *ctx = xctx; 

    ctx->real_thread_proc(); 
    return 0; 
} 

void OSCreateTask(OStypeTFP tFP, OStypeTcbP tcbP, OStypePrio prio) 
{ 
    pthread_attr_t threadAttrs; 
    pthread_t thread; 
    struct emu_OSCreateTask_thread_start_data *ctx = 
     malloc(sizeof(struct emu_OSCreateTask_thread_start_data)); 

    ctx->real_thread_proc = tFP; 

    pthread_attr_init(&threadAttributes); 
    pthread_create(&thread, &threadAttributes, 
        emu_OSCreateTask_shim_thread_proc, ctx); 
} 

注:ctx被分配在堆上,並泄露,因爲它需要活到後emu_OSCreateTask_shim_thread_proc回報,這可能是無限期晚於OSCreateTask回報。如果不知道更多關於您試圖模擬的API,我無法告訴您應該在哪裏存儲它以便在適當的時候釋放它,但有可能是的某處。也許在tcbP?注2:我使用上下文對象而不是填充pthread_create的上下文指針中的「real_thread_proc」(正如在Sergio的答案中),因爲我懷疑你會需要在墊片中做更多的東西,並且需要來自外部環境的更多數據來做到這一點。 (你是一個POSIX系統上,所以它安全的東西函數指針爲void *

+0

我想我們應該在'emu_OSCreateTask_shim_thread_proc()'返回之前''free''ctx'' – Sergio

+0

@Sergio不一定;它可能需要生存直到相當於'pthread_join'。 – zwol

+0

@zwol這是正確的答案,因爲它將指針包裝在結構中。我沒有理由在函數調用完成後不釋放,因爲pthread_join對傳遞的參數一無所知。創建的線程釋放內存是完全正確的。 – 2501