0

タスク (関数 + パラメーター) を投稿できるスレッド管理クラスを作成しています。クラスはそれらのスレッド化を処理します。

この問題はこのクラス全体にあまり関係していませんが (私が思うに)、複数のスレッドを使用するときに共有リソースをロックするという一般的な問題です。コードは次のとおりです。

メインのテスト ファイル:

#include <iostream>
#include <thread>
#include <vector>
#include "Ttask_1.h"
#include <mutex>

using namespace std;

bool quit=false;

void* square(void* n);
void* print(void* n);
mutex cout_mutex;
mutex res_mutex;

bool cout_locked=false;

vector<Ttask_1<void*,void*>*> tasks1;
vector<Ttask_1<void*,void*>*> tasks2;

void check_for_work(vector<void*> &vec,vector<Ttask_1<void*,void*>*> &tasks)
{
    while(!quit)
    {
        if(tasks.size()!=0)
        {
            (*tasks[0]).run(vec);
            tasks.erase(tasks.begin());
        }
        else
            quit=true;
    }
    while(cout_locked){}
    cout_locked=true;
    cout<<"thread done"<<endl;
    cout_locked=false;

}

int main(int argc, const char * argv[])
{
    vector<void*> vec;
    int n=5;
    //int *n_p=&n;
    //Ttask_1<void*,void*> task(&n,square);
    tasks1.push_back(new Ttask_1<void*,void*>(&n,square,true));
    tasks1.push_back(new Ttask_1<void*,void*>(&n,print,false));

    tasks2.push_back(new Ttask_1<void*,void*>(&n,square,true));
    tasks2.push_back(new Ttask_1<void*,void*>(&n,print,false));



    thread Thread1(check_for_work,ref(vec),ref(tasks2));


    thread Thread2(check_for_work,ref(vec),ref(tasks1));
    //(&Ttask_1<int,int>::run,&task,ref(vec));
   // task.run(vec,Thread);
    Thread1.join();
    Thread2.join();


    int a;
    cin>>a;
    return 0;
}

void* print(void* n)
{
    for(int i=0;i<*(int*)(n);i++)
    {
        while(cout_locked){}
        cout_locked=true;
        cout<<i<<endl;
        cout_locked=false;
    }
    void* a;
    return a;
}

void* square(void* n)
{

    int res=(*(int*)n)*(*(int*)n);

    while(cout_locked){}
    cout_locked=true;
    cout<<res<<endl;
    cout_locked=false;

    int *res_p=new int;
    res_p=&res;
    return res_p;
}

ttask_1 クラス:

#ifndef task_Test_Ttask_1_h
#define task_Test_Ttask_1_h
#include <vector>
#include <mutex>
using namespace std;

extern mutex res_mutex;

template <class type1, class ret>
class Ttask_1
{
public:
    Ttask_1(type1 arg_in,ret(*func_p_in)(type1),bool result)
    {
        safe_result=result;
        arg1=arg_in;
        func_p=func_p_in;
    }
    void run(vector<void*> &res_vector)
    {

        ret res=(*func_p)(arg1);

        if(safe_result)
        {
            void *res_p=&res;
            res_mutex.lock();
            res_vector.push_back(res_p);
            res_mutex.unlock();
        }
        done=true;

    }
    bool is_done(){return done;}
private:
    bool safe_result;
    bool done=false;
    type1 arg1;
    ret(*func_p)(type1);
};

#endif

ご覧のとおり、ミューテックスが機能していないことを確認した後、cout に独自の「ロック」機能を実装しました。動作はまったく同じなので、これは問題ではありません。

その動作は次のとおりです。

プログラムが終了する前に、数字 0、1、2、3、4、25 と文字列 'thread done' がすべて 2 回出力されることを期待しています。

ただし、非常に頻繁に(常にではありませんが、頻繁に)次の出力が得られます。

25 0 1 2 3 4 スレッド完了 スレッド完了

そのため、いくつかの数字が欠落しており、何が原因なのかわかりません。私が言ったように、私が自分のものを交換するなら

    while(cout_locked){}
    cout_locked=true;

    cout_mutex.locked();

    cout_locked=false;

    cout_mutex.unlock()

何も変わりません。

助けていただければ幸いです、ありがとう

4

2 に答える 2

1

あなたの主な問題は、それquitがグローバル変数であることです。1 つのスレッドが終了するとすぐに、もう一方のスレッドはそれ以上作業を行いません (まったく作業を行わないことも含まれます)。quitスレッドごとに -style 変数が必要になるかsize、while ループの条件として check を使用します。

また、ローカル変数のアドレスを関数vector内に入れるrunため、結果が予測できない場合があります。結果ベクトルを実際にタイプセーフにしないのはなぜですか?

とはいえ、コードには多くの機能的および慣用的な問題があります。

  • 変数はcout_locked機能しているように見えますが、競合状態がありますが、実際にはcoutロックする必要があるかどうかはわかりません。
  • あなたはvoid*、C++ が提供する型の安全性をそのままにしておけば、それを捨てるものとしてすべてを扱っています。
  • クラス内の初期化とコンストラクターの初期化を混在させます (コンストラクターで初期化しないのはなぜですかdone)。
  • 一般に、構築してから割り当てを行うというパフォーマンスへの影響を防ぐために、コンストラクター本体での割り当てよりもコンストラクター初期化子リストを優先します。
  • eraseベクトルから消去するのに最も効率の悪い場所であるベクトルの先頭から。キューに表示されている場合は、必要に応じてqueueまたはを使用dequeします。
  • printランダムポインタを返します。void*少なくとも返す必要がある場合は、一貫して null ( 0) を返します。
于 2013-06-25T18:58:43.073 に答える
0

このコードは、ローカル変数へのポインターを返しています。この変数は、アクセスされるまでに範囲外になります。また、メモリ リークも発生します。

int *res_p=new int;
res_p=&res;
return res_p;

intでローカルのアドレスを取得する代わりに、値で新しいを作成する必要があります&

return new int(res_p);

また、タスク ベクトルにアクセスするたびにロックする必要があります。

于 2013-06-25T18:56:43.703 に答える