Libtask是一个简单的协程库。它运行在Linux(ARM,MIPS和x86)上, FreeBSD(x86),OS X(PowerPC x86和x86-64)以及SunOS Solaris(Sparc), 并且很容易移植到其他系统。 Libtask为程序员提供了线程的错觉,但是 操作系统只能看到一个内核线程。 为清楚起见,我们将协同程序称为“任务”,而不是线程。 调度是合作的。一次只运行一个任务, 如果没有明确放弃,就无法重新安排 CPU。task.h中提供的大多数函数都有 睡觉的可能性。使用该任务的程序 函数应该#include < task.h >。 *基本任务操作 int taskcreate(void(* f)(void * arg),void * arg,unsigned int stacksize); 在堆栈大小stacksize上创建一个运行f(arg)的新任务。 void tasksystem(void); 将当前任务标记为“系统”任务。这些被忽略了 为了决定程序已经完成运行 (参见下一篇taskexit)。 void taskexit(int status); 退出当前任务。如果这是最后一次非系统任务, 使用给定的退出状态退出整个程序。 void taskexitall(int status); 使用给定的退出状态退出整个程序。 void taskmain(int argc,char * argv []); 写这个函数而不是main。Libtask提供自己的主要功能。 int taskyield(void); 明确放弃CPU。将安排当前任务 所有其他当前准备好的任务都有机会再次出现 跑步。返回在运行时运行的其他任务的数量 目前的任务正在等待 (零意味着没有其他任务 试图跑。) int taskdelay(unsigned int ms) 显式放弃CPU至少ms毫秒。 在此期间,其他任务继续运行。 void ** taskdata(void); 返回指向单个每任务void *指针的指针。 您可以将其用作每个任务存储位置。 void needstack(int n); 告诉任务库你需要至少n个字节 在堆栈上。如果没有,任务库将调用abort。 (很难弄清楚堆栈的大小。我通常会这么做 他们真的很大(比如32768),然后不用担心。) void taskname(char *,...); 采用像printf这样的参数列表。设置当前任务的名称。 char * taskgetname(void); 返回当前任务的名称。是实际的缓冲区; 不要自由。 void taskstate(char *,...); char * taskgetstate(void); 与taskname和taskgetname类似,但适用于任务状态。 当你发送一个任务程序一个SIGQUIT(或BSD上的SIGINFO) 它将打印所有任务及其名称和状态的列表。 这对于调试程序没有做任何事情的原因很有用! unsigned int taskid(void); 返回当前任务的唯一任务ID。 *非阻塞I / O. 对非阻塞I / O有少量的运行时支持 在文件描述符上。 int fdnoblock(int fd); 将给定fd上的I / O设置为非阻塞。应该 在任何其他fd例程之前调用。 int fdread(int,void *,int); 像常规的read()一样,但是在等待时将任务置于睡眠状态 数据而不是阻止整个程序。 int fdwrite(int,void *,int); 像常规的write()一样,但是在等待时将任务置于睡眠状态 写入数据而不是阻止整个程序。 void fdwait(int fd,int rw); 坐在fdread和fdwrite下面的低级调用。 在fd上等待I / O可以使任务进入休眠状态。 Rw指定I / O的类型:'r'表示读,'w'表示写, 其他任何意味着只有特殊情况(挂断等) 'r'和'w'也因特殊情况而醒来。 *网络I / O. 这些是丑陋的Unix套接字例程的方便包装。 他们都可以在通话期间将当前任务置于睡眠状态。 int netannounce(int proto,char * address,int port) 启动在协议的地址和端口上运行的网络侦听器。 Proto是TCP或UDP。端口号是端口号。地址是一个 主机名或IP地址的字符串版本。如果地址为空, 然后宣布绑定到所有可用接口上的给定端口。 返回与netaccept一起使用的fd。 示例:netannounce(TCP,“localhost”,80)或 netannounce(TCP,“127.0.0.1”,80)或netannounce(TCP,0,80)。 int netaccept(int fd,char * server,int * port) 获取进入侦听器fd的下一个连接。 返回一个用于与刚刚连接的人交谈的fd。 如果server不为null,则它必须至少指向一个缓冲区 用远程IP地址填写的16个字节。 如果port不为null,则使用报告端口填充它。 例: char server [16]; int port; if(netaccept(fd,server,&port)> = 0) printf(“从%s:%d连接”,服务器,端口); int netdial(int proto,char * name,int port) 创建与特定主机的新(传出)连接。 名称可以是IP地址或域名。如果是域名, 在解析名称时整个程序将被阻止 (DNS库不提供良好的非阻塞接口)。 示例:netdial(TCP,“www.google.com”,80) 或netdial(TCP,“18.26.4.9”,80) * 时间 unsigned int taskdelay(unsigned int ms) 将当前任务置于休眠状态大约ms毫秒。 返回睡眠的实际时间量,以毫秒为单位。 *示例程序 在这个目录中,tcpproxy.c是一个简单的TCP代理,用于说明 以上大部分内容。你可以跑 tcpproxy 1234 www.google.com 80 然后你应该能够访问http:// localhost:1234 /并查看谷歌。 其他例子是: primes.c - 简单的主筛 httpload.c - 简单的HTTP负载生成器 testdelay.c - test taskdelay() * 建造 要构建,运行make。您可以运行make install来复制task.h和 libtask.a到/ usr / local中的适当位置。然后你 应该能够在您的程序中与-ltask链接 使用它。 在SunOS Solaris计算机上,运行makesun而不是make。 *联系信息 如有疑问或问题,请给我发电子邮件 拉斯考克斯 rsc@swtch.com *你最初可能不会使用的东西 *但最终可能想知道 void tasksleep(Rendez *); int taskwakeup(Rendez *); int taskwakeupall(Rendez *); Rendez是一个条件变量。您可以声明一个新的 只是为它分配内存(或将其放在另一个结构中) 然后归零内存。Tasksleep(r)'睡在r',给予 上升CPU。多个任务可以在单个Rendez上休眠。 当另一个任务出现并调用taskwakeup(r)时, 睡在r上的第一个任务(如果有的话)将被唤醒。 Taskwakeupall(r)唤醒在r上睡觉的所有任务。 它们都返回唤醒的实际任务数。 void qlock(QLock *); int canqlock(QLock *); void qunlock(QLock *); 由于合作,你可能不需要锁 调度,但如果你这样做,这里有一些。你可以做一个新的 QLock只是声明它并将内存归零。 如果锁定由其他人持有,则调用qlock将放弃CPU。 调用qunlock不会放弃CPU。 调用canqlock尝试锁定锁,但不会放弃CPU。 如果获取了锁,则返回1,如果此时不能,则返回0。 void rlock(RWLock *); int canrlock(RWLock *); void runlock(RWLock *); void wlock(RWLock *); int canwlock(RWLock *); void wunlock(RWLock *); RWLocks是读写器锁。任意数量的读者 可以一次锁定它们,但一次只能锁定一个。 如果作家持有它,就不会有任何读者。 Channel * chancreate(int,int); 等等 通道是缓冲的通信管道 用于在任务之间发送消息。有些人喜欢 使用渠道完成大部分任务间通信。 有关频道的详细信息,请参阅频道的说明 http://swtch.com/usr/local/plan9/man/man3/thread.html和 http://swtch.com/~rsc/thread/ 并且还示例程序primes.c,它实现 并行的筛选。 源码:https://swtch.com/libtask/
Libtask:一个用于C和Unix的协同程序库,可以 编写事件驱动的程序而无需事件的麻烦! 可用于FreeBSD,Linux,OS X和Solaris
最新推荐文章于 2024-05-22 09:39:35 发布