メイン関数は libevent に基づいていますが、関数には長時間実行されるタスクがあります。したがって、タスクを実行するために N 回のスレッドを開始します。この考えは大丈夫ですか?また、C で libevent と pthread を一緒に使用する方法は?
4 に答える
このブログ投稿にマルチスレッド libevent の例があります: http://www.roncemer.com/multi-threaded-libevent-server-example
彼の解決策は、引用すると次のとおりです。
解決策は、アクティブな接続ごとに 1 つの libevent イベント キュー (別名 event_base) を作成し、それぞれに独自のイベント ポンプ スレッドを作成することです。このプロジェクトはまさにそれを行い、高性能でマルチスレッドの libevent ベースのソケット サーバーを作成するために必要なすべてを提供します。
それはうまくいくでしょう。
I/O コールバック関数では、時間のかかるジョブをスレッド プールの別のスレッドに委任します。正確なメカニズムは、ワーカー スレッドまたはスレッド プールのインターフェイスによって異なります。
ワーカー スレッドから I/O スレッドに結果を返すには、パイプを使用します。ワーカー スレッドが結果オブジェクトへのポインターをパイプに書き込み、I/O スレッドが起動してパイプからポインターを読み取ります。
注: これは libevent ではなく libev 用ですが、考え方は当てはまるかもしれません。
ここでは、コミュニティの例を示します。コメントして、顕著なバグがある場合はお知らせください。この例には、将来的にスレッドの終了と正常な終了のためのシグナル ハンドラが含まれる可能性があります。
//This program is demo for using pthreads with libev.
//Try using Timeout values as large as 1.0 and as small as 0.000001
//and notice the difference in the output
//(c) 2009 debuguo
//(c) 2013 enthusiasticgeek for stack overflow
//Free to distribute and improve the code. Leave credits intact
//compile using: gcc -g test.c -o test -lpthread -lev
#include <ev.h>
#include <stdio.h> // for puts
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t lock;
double timeout = 0.00001;
ev_timer timeout_watcher;
int timeout_count = 0;
ev_async async_watcher;
int async_count = 0;
struct ev_loop* loop2;
void* loop2thread(void* args)
{
// now wait for events to arrive on the inner loop
ev_loop(loop2, 0);
return NULL;
}
static void async_cb (EV_P_ ev_async *w, int revents)
{
//puts ("async ready");
pthread_mutex_lock(&lock); //Don't forget locking
++async_count;
printf("async = %d, timeout = %d \n", async_count, timeout_count);
pthread_mutex_unlock(&lock); //Don't forget unlocking
}
static void timeout_cb (EV_P_ ev_timer *w, int revents) // Timer callback function
{
//puts ("timeout");
if(ev_async_pending(&async_watcher)==false){ //the event has not yet been processed (or even noted) by the event loop? (i.e. Is it serviced? If yes then proceed to)
ev_async_send(loop2, &async_watcher); //Sends/signals/activates the given ev_async watcher, that is, feeds an EV_ASYNC event on the watcher into the event loop.
}
pthread_mutex_lock(&lock); //Don't forget locking
++timeout_count;
pthread_mutex_unlock(&lock); //Don't forget unlocking
w->repeat = timeout;
ev_timer_again(loop, &timeout_watcher); //Start the timer again.
}
int main (int argc, char** argv)
{
if (argc < 2) {
puts("Timeout value missing.\n./demo <timeout>");
return -1;
}
timeout = atof(argv[1]);
struct ev_loop *loop = EV_DEFAULT; //or ev_default_loop (0);
//Initialize pthread
pthread_mutex_init(&lock, NULL);
pthread_t thread;
// This loop sits in the pthread
loop2 = ev_loop_new(0);
//This block is specifically used pre-empting thread (i.e. temporary interruption and suspension of a task, without asking for its cooperation, with the intention to resume that task later.)
//This takes into account thread safety
ev_async_init(&async_watcher, async_cb);
ev_async_start(loop2, &async_watcher);
pthread_create(&thread, NULL, loop2thread, NULL);
ev_timer_init (&timeout_watcher, timeout_cb, timeout, 0.); // Non repeating timer. The timer starts repeating in the timeout callback function
ev_timer_start (loop, &timeout_watcher);
// now wait for events to arrive on the main loop
ev_loop(loop, 0);
//Wait on threads for execution
pthread_join(thread, NULL);
pthread_mutex_destroy(&lock);
return 0;
}