Ключевые слова:example, threads, (найти похожие документы)
Date: Mon, 4 Mar 2002 20:43:56 +0000 (UTC)
From: Vladimir Dozen <dozen@osw.com.ru>
Newsgroups: fido7.ru.unix.prog
Subject: Пример использования тредов.
> > В-третьих, возможно самому родить простые кооперативные нити
> А по подробнее, what's it?
Тебе это не подойдет, у тебя много параллельных read/write,
а у кооперативных нитей нить-то на самом деле одна, и если
она заснула на write(), то и остальные спят.
Для общего развития можешь посмотреть листинг. Список нитей
сделан страшно криво, но это был просто proof of concept.
Собрано под фряху, под линуксом надо заменить макрос SET_STACK_JB;
#include <iostream>
#include <stdexcept>
#include <setjmp.h>
#include <sys/types.h>
#include <dirent.h>
using namespace std;
// thread identificator type
typedef int jmpthread_t;
// maximum threads runned so far and current number of threads
int maxthread = 0;
int cntthread = 0;
jmpthread_t curthread = -1;
// thread contextes
jmp_buf threads[128];
// active (not terminated) threads has true in this
bool threads_used[128];
// thread starting routines addresses (see jmpthread_start())
typedef void(*jmpthread_start_t)(jmpthread_t);
jmpthread_start_t threads_start[128];
// context of main thread
jmp_buf mainthread;
#define stack_location(n) { char c; std::cout << tid \
<< ":stack for " << n << " is at " << std::hex << (void*)&c << std::endl; }
#define notify(msg,val) std::cout << tid << ":" << msg \
<< " value:" << val << std::endl
/**
* Machine-dependent stuff.
* Taken from FreeBSD:/usr/src/libc_r/uthreads/pthreads_private.h
*/
#define SET_STACK_JB(jb,stack) (jb)[0]._jb[2] = (int)(stack)
/**
* Reschedules a thread to run.
* Randomly chooses a thread to execute.
*/
void jmpthread_sched(jmpthread_t tid)
{
assert(cntthread>0);
int ntid;
while(true)
{
ntid = (int)(drand48()*maxthread);
if( threads_used[ntid] == true ) break;
}
curthread = ntid;
longjmp(threads[ntid],1);
}
/**
* Starts new thread.
* @return Thread id of newly created thread.
* @param start Address of thread procedure.
* @param stacksz Stack size for thread.
*/
jmpthread_t jmpthread_create(void (*start)(jmpthread_t),int stacksz=8192)
{
++maxthread;
++cntthread;
jmpthread_t iam = maxthread-1;
threads_used[iam] = true;
int rc = setjmp(threads[iam]);
if( rc == 0 )
{
// setup new stack
char* stk = (char*)malloc(stacksz+sizeof(jmp_buf));
SET_STACK_JB(threads[iam],stk+stacksz);
threads_start[iam] = start;
return iam;
}
else if( rc == 1 )
{
// run thread; we have moved stack, so we cannot use address
// of start from parameters and 'iam' from stack; use saved
// address and curthread instead
threads_start[curthread](curthread);
}
else
{
// unexpected error
exit(1);
}
return -1;
}
/**
* Stops thread.
*/
void jmpthread_exit(jmpthread_t tid)
{
threads_used[tid] = false;
--cntthread;
// no more threads; return to main routine
if( cntthread == 0 ) longjmp(mainthread,1);
jmpthread_sched(-1);
}
/**
* Passes control back to scheduler.
* @param tid Thread id of current thread.
*/
void jmpthread_yield(jmpthread_t tid)
{
// if we called from main routing, just pick a thread randomly
if( tid < 0 )
{
jmpthread_sched(tid);
return;
}
// save context
int rc = setjmp(threads[tid]);
if( rc == 0 )
{
// saved previous active thread; activate another
// choose random thread from list
jmpthread_sched(tid);
}
else if( rc == 1 )
{
// just reactivated
return;
}
else
{
// oops; error?
exit(1);
}
}
void f1(jmpthread_t tid)
{
stack_location("f1");
// to check we have correct stack pointer
int localdata = tid;
DIR* dir;
notify("entered f1",localdata);
dir = opendir("/etc");
jmpthread_yield(tid);
struct dirent* de;
while( (de = readdir(dir)) != 0 )
{
notify(de->d_name,localdata);
jmpthread_yield(tid);
}
closedir(dir);
notify("leaving f1",localdata);
jmpthread_exit(tid);
}
void my_main(jmpthread_t tid)
{
stack_location("my_main");
// thread id of created thread
jmpthread_t child = 0;
notify("entered my_main",child);
for( int i=0; i<4; ++i )
{
child = jmpthread_create(f1);
notify("created thread",child);
}
notify("leaving my_main",child);
jmpthread_exit(tid);
}
int main()
{
if( setjmp(mainthread) == 0 )
{
// schedule threads
jmpthread_t tid = -1;
jmpthread_t child = 0;
child = jmpthread_create(my_main);
notify("created thread",child);
while( cntthread > 0 ) jmpthread_yield(-1);
}
else
{
// called from jmpthread_exit: no more threads
}
return 0;
}
--
dozen @ home