Aros/开发者/文档/库/线程
由Rob Norris 2007年12月1日和3日创建,为Aros提供一些线程可能性,以帮助他移植名为Traveller的webkit。 pthreads在Aros中不受支持。线程被引入以提供比进程(任务)更低的系统开销。
作者:Robert Norris <[email protected]> 最后更新: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)