Aros/開發者/文件/庫/執行緒
由Rob Norris 2007年12月1日和3日建立,為Aros提供一些執行緒可能性,以幫助他移植名為Traveller的webkit。 pthreads在Aros中不受支援。執行緒被引入以提供比程序(任務)更低的系統開銷。
作者:Robert Norris <rob@cataclysm.cx> 最後更新:2007-11-30
這是一個簡單的庫,為更高級別的庫和應用程式提供基本的執行緒和同步原語。它目前提供以下內容
- 執行緒
- 互斥鎖
- 條件變數
這是一個正在進行的工作。如果您使用它,可能會發生奇怪的事情。如果您發現某些內容無法按照您的意願或預期的方式工作,請告訴我。介面和語義都是流動的,因此您可以根據需要進行更改,但另一方面,您需要跟蹤應用程式中對庫的更改。
此庫刻意設計為不使用 POSIX 執行緒。我希望它可以用來實現它們,但它永遠不會成為那樣。 POSIX 執行緒語義比我想要在這個級別上處理的要複雜。
在這個階段,最大的遺漏是強制執行緒退出的一種方法。很難做到,因為無法知道執行緒當前打開了哪些資源以便關閉它們。我有一些想法,但我不知道是否可以在沒有適當的任務資源跟蹤的情況下做到這一點。
類似地,當您的應用程式或庫關閉 thread.library(在應用程式中,這通常會在 main() 退出時發生)時,它將等待所有仍在執行的執行緒完成。當發生這種情況時,您將在核心日誌中收到一些警告。當執行緒仍在執行時,不允許主程序退出,因為主執行緒通常持有執行緒需要的資源,這些資源將線上程退出時被釋放,例如程式程式碼本身。只要執行緒在與主程序相同的地址空間中執行,就幾乎無能為力。
這也使得分離執行緒毫無意義。分離執行緒語義是在希望將來能夠完全實現的希望下提供的。
待辦事項
- 一種優雅地要求執行緒退出的方法(讓執行緒有機會清理)
- 一種等待所有執行緒完成的方法(包括分離執行緒,因此這可以有效地用於在 main() 中退出之前等待執行緒)。
- 一種真正分離正在執行的執行緒的方法,以便它們可以在主程序退出後繼續存在。
- 當執行緒仍在執行時,退出主程序是否可以更好地處理?
- 讀/寫(“可提升”)互斥鎖,您可以在已將它作為共享鎖持有時請求排它地獲取鎖。這可以在某些情況下避免競爭。
當主任務線上程仍在執行時退出時該怎麼辦。可能會發生很多糟糕的事情,但最好的辦法是簡單地分離執行緒並讓它們繼續執行。
POSIX pthreads 提供執行緒管理、互斥鎖變數(同步)和條件變數(更多同步,但依賴於互斥鎖鎖定)。
必須包含,宣告 struct Library *ThreadBase,並使用 OpenLibrary()/CloseLibrary() 開啟/關閉庫。你需要 proto/thread.h,它會為你包含 clib/thread_protos.h。
thread.library 的當前版本號是多少(OpenLibrary() 呼叫)? 當前版本是什麼,我只使用 0。
如果您使用任何套接字,請不要忘記開啟 bsdsocket.library。
uint32_t id = CreateThread(entry, data);
if (id < 0)
printf("thread creation failed\n");
else
printf("thread %d created\n", id);
void *ret; WaitThread(id, &ret);
#include <libraries/thread.h>
#include <proto/thread.h>
#include <proto/dos.h>
#include <stdio.h>
#include <stdint.h>
void *thread_main(void *data) {
ThreadIdentifier id = CurrentThread();
int i;
printf("[%d] starting\n", id);
for (i = 0; i < 10; i++) {
printf("[%d] count: %d\n", id, i);
Delay(25);
}
printf("[%d] exiting\n", id);
return NULL;
}
int main (int argc, char **argv) {
ThreadIdentifier t1, t2;
t1 = CreateThread(thread_main, NULL);
printf("created thread %d\n", t1);
Delay(100);
t2 = CreateThread(thread_main, NULL);
printf("created thread %d\n", t2);
printf("waiting for thread %d\n", t2);
WaitThread(t2, NULL);
printf("thread %d completed\n", t2);
printf("waiting for thread %d\n", t1);
WaitThread(t1, NULL);
printf("thread %d completed\n", t1);
return 0;
}
#include <libraries/thread.h>
#include <proto/thread.h>
#include <proto/dos.h>
#include <stdio.h>
void *thread_main(void *data) {
ThreadIdentifier id = CurrentThread();
printf("[%d] starting\n", id);
Delay(50);
printf("[%d] exiting\n", id);
return (void *) id;
}
int main (int argc, char **argv) {
int i;
ThreadIdentifier id[10], ret;
for (i = 0; i < 10; i++) {
id[i] = CreateThread(thread_main, NULL);
printf("created thread %d\n", id[i]);
Delay(25);
}
for (i = 0; i < 10; i++) {
printf("waiting for thread %d\n", id[i]);
WaitThread(id[i], (void **) &ret);
printf("thread %d return %d\n", id[i], ret);
}
return 0;
}
Mutex mutex = CreateMutex();
LockMutex(mutex); WaitCondition(cond, mutex); UnlockMutex(mutex);
#include <libraries/thread.h>
#include <proto/thread.h>
#include <proto/dos.h>
#include <stdio.h>
#include <stdint.h>
void *locker_thread(void *data) {
Mutex mutex = (Mutex) data;
ThreadIdentifier id = CurrentThread();
printf("[%d] starting, locking the mutex\n", id);
LockMutex(mutex);
printf("[%d] got it, pausing for 5s\n", id);
Delay(250);
printf("[%d] unlocking the mutex\n", id);
UnlockMutex(mutex);
printf("[%d] all done, exiting\n", id);
return NULL;
}
void *waiter_thread(void *data) {
Mutex mutex = (Mutex) data;
ThreadIdentifier id = CurrentThread();
printf("[%d] starting, locking the mutex\n", id);
LockMutex(mutex);
printf("[%d] got it, unlocking\n", id);
UnlockMutex(mutex);
printf("[%d] all done, exiting\n", id);
return NULL;
}
int main (int argc, char **argv) {
Mutex mutex;
ThreadIdentifier tl, tw;
printf("creating mutex\n");
mutex = CreateMutex();
printf("starting locker thread\n");
tl = CreateThread(locker_thread, (void *) mutex);
printf("sleeping for 2s\n");
Delay(100);
printf("starting waiter thread\n");
tw = CreateThread(waiter_thread, (void *) mutex);
printf("waiting for locker thread to exit\n");
WaitThread(tl, NULL);
printf("waiting for waiter thread to exit\n");
WaitThread(tw, NULL);
printf("destroying the mutex\n");
DestroyMutex(mutex);
printf("all done\n");
return 0;
}
BroadcastCondition() CreateCondition() DestroyCondition() WaitCondition() SignalCondition()
[編輯 | 編輯原始碼]#include <exec/memory.h>
#include <libraries/thread.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/thread.h>
#include <stdio.h>
#include <stdint.h>
struct thread_data {
Mutex mutex;
Condition cond;
};
void *waiter_thread(void *data) {
struct thread_data *td = (struct thread_data *) data;
ThreadIdentifier id = CurrentThread();
printf("[%d] starting, locking the mutex\n", id);
LockMutex(td->mutex);
printf("[%d] waiting on the condition\n", id);
WaitCondition(td->cond, td->mutex);
printf("[%d] condition signalled, unlocking the mutex\n", id);
UnlockMutex(td->mutex);
printf("[%d] all done, exiting\n", id);
return NULL;
}
int main (int argc, char **argv) {
struct thread_data *td;
int i;
td = AllocMem(sizeof(struct thread_data), MEMF_PUBLIC | MEMF_CLEAR);
printf("creating mutex\n");
td->mutex = CreateMutex();
printf("creating condition\n");
td->cond = CreateCondition();
printf("starting waiter threads\n");
for (i = 0; i < 5; i++)
CreateThread(waiter_thread, (void *) td);
printf("sleeping for 2s\n");
Delay(100);
printf("signalling condition\n");
SignalCondition(td->cond);
printf("sleeping for 2s\n");
Delay(100);
printf("broadcasting condition\n");
BroadcastCondition(td->cond);
printf("waiting for threads to exit\n");
WaitAllThreads();
printf("destroying the condition\n");
DestroyCondition(td->cond);
printf("destroying the mutex\n");
DestroyMutex(td->mutex);
FreeMem(td, sizeof(struct thread_data));
printf("all done\n");
return 0;
}
#include <exec/memory.h>
#include <libraries/thread.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/thread.h>
#include <stdio.h>
#include <stdint.h>
struct thread_data {
Mutex mutex;
Condition cond;
};
void *waiter_thread(void *data) {
struct thread_data *td = (struct thread_data *) data;
ThreadIdentifier id = CurrentThread();
printf("[%d] starting, locking the mutex\n", id);
LockMutex(td->mutex);
printf("[%d] waiting on the condition\n", id);
WaitCondition(td->cond, td->mutex);
printf("[%d] condition signalled, unlocking the mutex\n", id);
UnlockMutex(td->mutex);
printf("[%d] all done, exiting\n", id);
return NULL;
}
int main (int argc, char **argv) {
struct thread_data *td;
ThreadIdentifier tw;
td = AllocMem(sizeof(struct thread_data), MEMF_PUBLIC | MEMF_CLEAR);
printf("creating mutex\n");
td->mutex = CreateMutex();
printf("creating condition\n");
td->cond = CreateCondition();
printf("starting waiter thread\n");
tw = CreateThread(waiter_thread, (void *) td);
printf("sleeping for 2s\n");
Delay(100);
printf("signalling condition\n");
SignalCondition(td->cond);
printf("waiting for waiter thread\n");
WaitThread(tw, NULL);
printf("destroying the condition\n");
DestroyCondition(td->cond);
printf("destroying the mutex\n");
DestroyMutex(td->mutex);
FreeMem(td, sizeof(struct thread_data));
printf("all done\n");
return 0;
}
實現執行緒的另一種方法(在Aros中未使用)。
/* sys_thrad.h */
struct SysThread;
struct SysMutex;
enum SysThreadPriority
{
SYSTHREAD_PRIORITY_LOW,
SYSTHREAD_PRIORITY_NORMAL,
SYSTHREAD_PRIORITY_HIGH,
};
struct SysThread *Sys_Thread_CreateThread(void (*entrypoint)(void *), void *argument);
void Sys_Thread_DeleteThread(struct SysThread *thread);
int Sys_Thread_SetThreadPriority(struct SysThread *thread, enum SysThreadPriority priority);
struct SysMutex *Sys_Thread_CreateMutex(void);
void Sys_Thread_DeleteMutex(struct SysMutex *mutex);
void Sys_Thread_LockMutex(struct SysMutex *mutex);
void Sys_Thread_UnlockMutex(struct SysMutex *mutex);
/*
Copyright (C) 2008-2011 Mark Olsen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <exec/semaphores.h>
#include <dos/dos.h>
#include <dos/dostags.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include "sys_thread.h"
struct SysThread
{
struct MsgPort *msgport;
struct Message msg;
struct Process *process;
void (*entrypoint)(void *);
void *argument;
};
struct SysMutex
{
struct SignalSemaphore sem;
};
static void Sys_Thread_Trampoline()
{
struct SysThread *thread;
thread = FindTask(0)->tc_UserData;
thread->entrypoint(thread->argument);
Forbid();
ReplyMsg(&thread->msg);
}
struct SysThread *Sys_Thread_CreateThread(void (*entrypoint)(void *), void *argument)
{
struct SysThread *thread;
thread = AllocVec(sizeof(*thread), MEMF_ANY);
if (thread)
{
thread->msgport = CreateMsgPort();
if (thread->msgport)
{
thread->msg.mn_Node.ln_Type = NT_MESSAGE;
thread->msg.mn_ReplyPort = thread->msgport;
thread->msg.mn_Length = sizeof(thread->msg);
thread->entrypoint = entrypoint;
thread->argument = argument;
thread->process = CreateNewProcTags(NP_Entry, Sys_Thread_Trampoline,
NP_UserData, thread,
NP_Name, "Fodquake Thread",
NP_StackSize, 32768,
TAG_DONE);
if (thread->process)
{
return thread;
}
DeleteMsgPort(thread->msgport);
}
FreeVec(thread);
}
return 0;
}
void Sys_Thread_DeleteThread(struct SysThread *thread)
{
SetTaskPri(&thread->process->pr_Task, 0);
while(!GetMsg(thread->msgport))
WaitPort(thread->msgport);
DeleteMsgPort(thread->msgport);
FreeVec(thread);
}
int Sys_Thread_SetThreadPriority(struct SysThread *thread, enum SysThreadPriority priority)
{
int pri;
switch(priority)
{
case SYSTHREAD_PRIORITY_LOW:
pri = -1;
break;
case SYSTHREAD_PRIORITY_HIGH:
pri = 4;
break;
default:
pri = 0;
break;
}
SetTaskPri(&thread->process->pr_Task, pri);
return 0;
}
struct SysMutex *Sys_Thread_CreateMutex(void)
{
struct SysMutex *mutex;
mutex = AllocVec(sizeof(*mutex), MEMF_ANY);
if (mutex)
{
InitSemaphore(&mutex->sem);
return mutex;
}
return 0;
}
void Sys_Thread_DeleteMutex(struct SysMutex *mutex)
{
FreeVec(mutex);
}
void Sys_Thread_LockMutex(struct SysMutex *mutex)
{
ObtainSemaphore(&mutex->sem);
}
void Sys_Thread_UnlockMutex(struct SysMutex *mutex)
{
ReleaseSemaphore(&mutex->sem);
}
uint32_t CreateThread(ThreadEntryFunction entry, void *data) BOOL WaitThread(uint32_t thread_id, void **result) void WaitAllThreads() BOOL DetachThread(uint32_t thread_id) uint32_t CurrentThread() void *CreateMutex() BOOL DestroyMutex(void *mutex) void LockMutex(void *mutex) BOOL TryLockMutex(void *mutex) void UnlockMutex(void *mutex) void *CreateCondition() BOOL DestroyCondition(void *cond) BOOL WaitCondition(void *cond, void *mutex) void SignalCondition(void *cond) void BroadcastCondition(void *cond) void ExitThread(void *result)