12

私には2つのスレッドがあります。1つはタイトなループで動作し、もう1つは時々最初のスレッドとの同期を実行する必要があります。

// thread 1
while(1)
{
    lock(work);
    // perform work
    unlock(work);
}

// thread 2
while(1)
{
    // unrelated work that takes a while
    lock(work);
    // synchronizing step
    unlock(work);
}

私の意図は、スレッド2がロックを取得することにより、スレッド1を効果的に一時停止し、必要な同期を実行できるようにすることです。スレッド1は、ロックを解除して一時停止することもできます。スレッド2がロックを待機していない場合は、再度ロックして作業に戻ります。

私が遭遇した問題は、ミューテックスが公平ではないため、スレッド1がミューテックスをすばやく再ロックしてスレッド2を枯渇させることです。使用しようとしましたがpthread_yield、これまでのところ問題なく動作しているようですが、すべてのシステム/コアの数。マルチコアシステムであっても、スレッド1が常にスレッド2に譲ることを保証する方法はありますか?

この同期プロセスを処理する最も効果的な方法は何ですか?

4

5 に答える 5

8

次の行に沿って、pthreadミューテックスの上にFIFO「チケットロック」を構築できます。

#include <pthread.h>

typedef struct ticket_lock {
    pthread_cond_t cond;
    pthread_mutex_t mutex;
    unsigned long queue_head, queue_tail;
} ticket_lock_t;

#define TICKET_LOCK_INITIALIZER { PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER }

void ticket_lock(ticket_lock_t *ticket)
{
    unsigned long queue_me;

    pthread_mutex_lock(&ticket->mutex);
    queue_me = ticket->queue_tail++;
    while (queue_me != ticket->queue_head)
    {
        pthread_cond_wait(&ticket->cond, &ticket->mutex);
    }
    pthread_mutex_unlock(&ticket->mutex);
}

void ticket_unlock(ticket_lock_t *ticket)
{
    pthread_mutex_lock(&ticket->mutex);
    ticket->queue_head++;
    pthread_cond_broadcast(&ticket->cond);
    pthread_mutex_unlock(&ticket->mutex);
}

この種のスキームでは、スレッドがチケットロックで保護されたクリティカルセクション内にある間、低レベルのpthreadsミューテックスは保持されず、他のスレッドがキューに参加できるようになります。

于 2012-10-03T07:12:18.320 に答える
5

あなたの場合、条件変数を使用して、必要なすべての操作を起動して実行する必要があるときに2番目のスレッドに通知することをお勧めします。

于 2012-10-02T06:13:37.160 に答える
3

pthreadAPIでスレッド優先度の概念を提供します。2つのスレッドがミューテックスを介して競合している場合、スケジューリングポリシーによって、どちらがミューテックスを取得するかが決定されます。この関数pthread_attr_setschedpolicyを使用すると、それを設定できpthread_attr_getschedpolicy、情報を取得できます。

今悪いニュース:

  • 2つのスレッドだけがミューテックスをロック/ロック解除しているとき、私はどんな種類の競争も見ることができません。アトミック命令を実行する最初の人がそれを取り、他のブロックを取ります。この属性がここに適用されるかどうかはわかりません。
  • この関数はさまざまなパラメーター(、、、および)をとることができますSCHED_FIFOが、このSCHED_RR質問は、Linuxでのみサポートされていると回答されています)SCHED_OTHERSCHED_SPORADICSCHED_OTHER

ですから、私があなたなら、それを試してみますが、あまり期待しないでください。pthread_yield私にはもっと有望なようです。詳細については、こちらをご覧ください

于 2012-10-02T06:36:48.450 に答える
0

上記のチケットロックは最高のようです。ただし、pthread_yieldが機能することを保証するために、boolを待機させることができます。これは、thread2によって設定およびリセットされます。ブール待機が設定されている限り、thread1は降伏します。

于 2013-09-16T14:19:12.290 に答える
0

これがあなたのケース(2つのスレッド)で機能する簡単な解決策です。使用している場合std::mutex、このクラスはドロップインの代替品です。ミューテックスをこのタイプに変更すると、一方のスレッドがロックを保持し、もう一方のスレッドがロックを待機している場合、最初のスレッドがロック解除されると、最初のスレッドが再びロックする前に、2番目のスレッドがロックを取得することが保証されます。

3つ以上のスレッドがたまたまミューテックスを同時に使用した場合でも機能しますが、公平性は保証されません。

プレーンpthread_mutex_tを使用している場合は、この例に従ってロックコードを簡単に変更できます(ロック解除は変更されません)。

#include <mutex>

// Behaves the same as std::mutex but guarantees fairness as long as
// up to two threads are using (holding/waiting on) it.
// When one thread unlocks the mutex while another is waiting on it,
// the other is guaranteed to run before the first thread can lock it again.

class FairDualMutex : public std::mutex {
public:
    void lock() {
        _fairness_mutex.lock();
        std::mutex::lock();
        _fairness_mutex.unlock();
    }
private:
    std::mutex _fairness_mutex;
};
于 2017-10-24T08:37:19.887 に答える