0

私は pthread を練習しています。

私の元のプログラムでpushは、 というクラスのインスタンスが共有キューに送信されますが、request最初に、何かを共有キューにプッシュしていることを確認したいと考えています。

これは非常に単純なコードですが、理由がわからないエラーがたくさんスローされるだけです。

おそらく構文だと思いますが、何を試してもうまくいきませんでした。

機能しない理由がわかりますか?

以下は私が試してきたコードです。

extern "C" {
    #include<pthread.h>
    #include<unistd.h>
}
#include<queue>
#include<iostream>
#include<string>

using namespace std;

class request {
 public:
    string req;
    request(string s) : req(s) {}

};

int n;
queue<request> q;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;

void * putToQueue(string);

int main ( void ) {
    pthread_t t1, t2;

    request* ff = new request("First");
    request* trd = new request("Third");

    int result1 = pthread_create(&t1, NULL, &putToQueue, reinterpret_cast<void*>(&ff));
    if (result1 != 0) cout << "error 1" << endl;
    int result2 = pthread_create(&t2, NULL, &putToQueue, reinterpret_cast<void*>(&trd));
    if (result2 != 0) cout << "error 2" << endl;

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    for(int i=0; i<q.size(); ++i) {
        cout << q.front().req << " is in queue" << endl;
        q.pop();
        --n;
    }

    return 0;
}

void * putToQueue(void* elem) {
    pthread_mutex_lock(&mut);

    q.push(reinterpret_cast<request>(elem));
    ++n;

    cout << n << " items are in the queue." << endl;

    pthread_mutex_unlock(&mut);
    return 0;
}
4

2 に答える 2

1

以下のコードは、変更が必要だったすべてについてコメントしています。なぜ変更しなければならなかったのかを詳しく説明したいと思いますが、コードがそれ自体を物語っていることを願っています。まだ防弾ではありません。別の方法やより良い方法 ( failed の例外処理など) はたくさんありますnewが、少なくともコンパイル、実行、およびメモリ リークはありません。

#include <queue>
#include <iostream>
#include <string>
#include <pthread.h>
#include <unistd.h>
using namespace std;

// MINOR: param should be a const-ref
class request {
public:
    string req;
    request(const string& s) : req(s) {}
};

int n;
queue<request> q;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;


// FIXED: made protoype a proper pthread-proc signature
void * putToQueue(void*);

int main ( void )
{
    pthread_t t1, t2;

    // FIXED: made thread param the actual dynamic allocation address
    int result1 = pthread_create(&t1, NULL, &putToQueue, new request("First"));
    if (result1 != 0) cout << "error 1" << endl;

    // FIXED: made thread param the actual dynamic allocation address
    int result2 = pthread_create(&t2, NULL, &putToQueue, new request("Third"));
    if (result2 != 0) cout << "error 2" << endl;

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    // FIXED: was skipping elements because the queue size was shrinking
    //  with each pop in the while-body.
    while (!q.empty())
    {
        cout << q.front().req << " WAS in queue" << endl;
        q.pop();
    }

    return 0;
}

// FIXED: pretty much a near-total-rewrite
void* putToQueue(void* elem)
{
    request *req = static_cast<request*>(elem);
    if (pthread_mutex_lock(&mut) == 0)
    {
        q.push(*req);
        cout << ++n << " items are in the queue." << endl;
        pthread_mutex_unlock(&mut);
    }
    delete req; // FIXED: squelched memory leak
    return 0;
}

出力(あなたのもの異なる場合があります)

1 items are in the queue.
2 items are in the queue.
Third WAS in queue
First WAS in queue
于 2013-10-31T00:40:22.573 に答える
1

コメントに記載されているように、pthreads の直接使用をスキップし、代わりに C++11 スレッド化プリミティブを使用することをお勧めします。単純な保護されたキュー クラスから始めます。

template <class T, template<class, class> class Container=std::deque>
class p_q {
    typedef typename Container<T, std::allocator<T>> container;
    typedef typename container::iterator iterator;

    container data;
    std::mutex m;
public:
    void push(T a) {
        std::lock_guard<std::mutex> l(m);
        data.emplace_back(a);
    }
    iterator begin() { return data.begin(); }
    iterator end() { return data.end(); }
    // omitting front() and pop() for now, because they're not used in this code
};

これを使用すると、コードのメイン ストリームは、次のようなシングル スレッド コードとほぼ同じくらいシンプルでクリーンなままになります。

int main() {
    p_q<std::string> q;

    auto pusher = [&q](std::string const& a) { q.push(a); };

    std::thread t1{ pusher, "First" };
    std::thread t2{ pusher, "Second" };

    t1.join();
    t2.join();

    for (auto s : q)
        std::cout << s << "\n";
}

現状では、これは複数のプロデューサー、単一のコンシューマーのキューです。さらに、消費が発生しているときにプロデューサーが実行されていないという事実に依存します。この場合はそうですが、常にそうであるとは限りません。そうでない場合は、キューへの書き込み時だけでなく、キューからの読み取り/ポップ時にロックを行う (わずかに) より複雑なキューが必要になります。

于 2013-10-31T01:48:48.263 に答える