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' 在程序终止之前都被打印两次。

然而,很多时候(不总是,但经常)我得到这个输出:

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是一个全局变量。一旦一个线程完成,另一个线程就不会再做任何工作(这可能包括根本不做任何工作)。每个线程都需要一个quit-style 变量,或者只使用size检查作为 while 循环的条件。

您还将局部变量的地址放入函数vector内部run,因此您的结果可能无法预测。为什么不让结果向量实际上是类型安全的?

也就是说,您的代码存在许多功能和惯用问题:

  • cout_locked变量似乎只起作用,那里存在竞争条件 - 但我实际上不确定是否cout需要锁定。
  • 您将所有内容都视为void*丢弃了 C++ 提供的如此多的类型安全性,如果您只是允许它的话。
  • 您将类内初始化与构造函数初始化混合在一起(为什么不在构造函数中进行初始化done)。
  • 通常更喜欢构造函数初始值设定项列表而不是构造函数主体中的赋值,以防止构造后赋值的性能影响。
  • erase从向量的开头开始,这是从向量中擦除效率最低的位置。如果它在队列中表示,请使用queuedeque根据您的需要。
  • 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 回答