1

私は通常、シグナルハンドラーでシングルスレッドプロセスを使用し、並列タスクを複数のプロセスに分割することで並行性を実現します。

今、私はマルチスレッドがより速くなることができるかどうかをチェックしようとしています。アラーム/タイマーを実装するために、私は通常、alarmHandlersを登録し、OSにシグナルを送信させます。しかし、マルチスレッド環境では、このアプローチを採用することはできません。ただし、シグナルを特定のスレッドに配信できるようにする方法があります。

したがって、私の質問は、マルチスレッド環境でタイマーを実装する方法ですか?スレッドを開始し、必要な量だけスリープさせてから、共有変数を設定できます。他にどのようなオプションがありますか?

4

3 に答える 3

2

異なる時間にスレッドを開始したいと思います。sleep_until 関数を使用できます。これは C++11 関数です スレッドは特定の瞬間までスリープします http://en.cppreference.com/w/cpp/thread/sleep_until

したがって、コードを実行するタスクがいくつかある場合は、次のようになります。

int PerformTask(const std::chrono::time_point<Clock,Duration>& sleep_time, TaskParameters)
{
     sleep_until(sleep_time);
     PerformTask(TaskParameters);
}

それが役立つことを願って、

于 2013-08-20T22:29:14.263 に答える
1

使用している環境 (OS、API など) を指定しないため、得られる回答はかなり一般的なものでなければなりません。

スレッドを開始してしばらくスリープさせてから共有変数を設定するという例から、あなたがやろうとしているのは、特定の時間に複数のスレッドすべてに何か特別なことをさせることですよね?

もしそうなら、それを行う簡単な方法の 1 つは、スレッドを生成する前にアラーム時刻を選択することです。これにより、各スレッドはいつ特別なアクションを実行するかを事前に知ることができます。次に、「時計を見て」指定された時間にアクションを実行するように各スレッドをコーディングするだけです。

しかし、アラームが鳴る時刻が事前にわからないとしましょう。その場合、必要なのはスレッド間通信の仕組みだと思います。あるスレッドがシグナル/メッセージを別のスレッドに送信する方法を取得したら、それを使用して、アラームアクションを実行する時間になったときにターゲットスレッドに通知できます。

これを行うためのさまざまな API がありますが、私が好んで使用する方法 (クロスプラットフォームで移植可能であり、標準の BSD ソケット API を使用するため) は、各スレッドを生成する前に完全にローカルなソケット接続を作成することです。Unix/Posix では、socketpair() を呼び出すことで、これを非常に簡単に行うことができます。Windows では、呼び出す socketpair() 関数はありませんが、通常のネットワーク呼び出し (socket()、bind()、listen()、accept() を 1 つのソケットに対して使用してから、socket( ) と connect() でもう一方のソケットを作成し、それを最初の端に接続します)。

接続されたソケットのペアを取得したら、親スレッドに最初のソケットのみを保持させ、新しく生成されたスレッドに 2 番目のソケットのみを保持させます。これで、親スレッドと子スレッドがソケットを介して相互に通信できるようになりました。たとえば、親スレッドが子スレッドに何かをさせたい場合、そのソケットでバイトを send() でき、子スレッドはソケットでそのバイトを recv() します。子スレッドが親に指示したい場合はその逆です何かをします。

このようにして、親スレッドは一連のスレッドを生成し、アラーム時刻が到来したときに各スレッドのソケットでバイトを送信できます。その間、子スレッドは作業を行い、ノンブロッキング recv() 呼び出しを介してソケットをポーリングするか、アラームを待っている間にスリープすることを好む場合は、select() または recv() などの内部でブロックできます。

必要がない場合は、socketpair を介してすべてのクロススレッド データを送信する必要はないことに注意してください。通常、ミューテックスをロックし、コマンド オブジェクトを FIFO キューに追加し、ミューテックスをロック解除してから、1 バイトを送信します。子スレッドがそのバイトを受け取ると、同じミューテックスをロックし、FIFO キューからコマンド オブジェクトを取り出し、ミューテックスをロック解除し、コマンドを実行することで応答します。そうすれば、共有メモリを使用して、ソケットを介して大量のバイトを送信することなく、任意に大量のデータを子スレッドに「送信」できます。送信される 1 バイトは、子スレッドをウェイクアップするための「シグナル」としてのみ機能します。

于 2013-02-03T04:16:54.527 に答える
1

boost::asio でタイマーを実装する

これは、私たちのプロジェクトで使用したタイマー クラスのウィッチです。ウィッチ プロジェクトは、4Gbit/s のインターネット フロー (約 300 万から 400 万のタイマー) を扱います。タイマーは、ほとんどの一般的な作業に適しています。

timer.h

/*
 * Timer
 * Licensed under Apache
 *
 * Author: KaiWen <wenkai1987@gmail.com>
 * Date: Apr-16-2013
 *
 */
#ifndef TIMER_H
#define TIMER_H

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/unordered_map.hpp>

typedef boost::asio::deadline_timer* timer_ptr;

namespace bs = boost::system;

class timer;
class timer_node;

class tm_callback {
public:
    explicit tm_callback(boost::function<void(timer_node&)>& f) : m_f(f)
    {
    }

    void operator()(timer_node& node, const bs::error_code& e) {
        if (!e)
            m_f(node);
    }
private:
    boost::function<void(timer_node&)> m_f;
};

class timer_node {
    friend class timer;
public:
    timer_node() {}
    timer_node(timer_ptr p, int ms, boost::function<void(timer_node&)> f) :
        m_tptr(p), m_ms(ms), m_callback(f)
    {
    }

    void reset(unsigned int ms = 0, boost::function<void(timer_node&)> f = 0) {
        if (ms)
            m_tptr->expires_from_now(boost::posix_time::milliseconds(ms));
        else
            m_tptr->expires_from_now(boost::posix_time::milliseconds(m_ms));

        if (f)
            m_tptr->async_wait(boost::bind<void>(tm_callback(f), *this, _1));
        else
            m_tptr->async_wait(boost::bind<void>(tm_callback(m_callback), *this, _1));
    }
private:
    timer_ptr m_tptr;
    int m_ms;
    boost::function<void(timer_node&)> m_callback;
};

タイマー.cpp

/*
 * Timer
 *
 * Licensed under Apache
 *
 * Author: KaiWen <wenkai1987@gmail.com>
 * Date: Apr-16-2013
 *
 */
#include "timer.h"
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/ptime.hpp>

namespace ba = boost::asio;

timer::timer(int thread_num) : m_next_ios(0), m_size(0) {
    for (int i = 0; i < thread_num; i++) {
        io_service_ptr p(new ba::io_service);
        work_ptr pw(new ba::io_service::work(*p));
        m_ios_list.push_back(p);
        m_works.push_back(pw);
    }

    pthread_spin_init(&m_lock, 0);
}

timer::~timer() {
    pthread_spin_destroy(&m_lock);
}

void timer::run() {
    for (size_t i = 0; i < m_ios_list.size(); i++)
        m_threads.create_thread(boost::bind(&ba::io_service::run, &*m_ios_list[i]))->detach();
}

必要に応じて、timer.cpp を timer.h に結合すると、ヘッダー ファイルだけになります。簡単な使い方:

#include <stdio.h>
#include "timer.h"

timer t(3);

void callback(timer_node& nd) {
    std::cout << "time out" << std::endl;
    t.del_timer(nd);
}

int main(void) {
    t.run();

    t.add_timer(5000, callback);    // set timeout 5 seconds

    sleep(6);

    return 0;
}

スレッド特殊タイマーを実装する

上記のタイマーにロックがあり、プログラムがあまり速くありません。オーウェンスレッドの特別なタイマーを実装できます。ロックを使用せず、ブロックせず、上記のタイマーよりも高速ですが、これには「ドライバー」が必要であり、実装はほとんどありません。これを実装する方法は次のとおりです。

pkt = get_pkt();
if (pkt) {
    now = pkt->sec;
    timer.execut_timer(now);
}

さて、ここではロックもブロックもせず、パフォーマンスを向上させます。これを使用して、10GBit/s のインターネット フロー (約 800 万から 900 万のタイマー) を処理します。しかし、これは実装依存です。お役に立てれば幸いです。

于 2013-08-21T01:30:38.730 に答える