类对象上的多线程

Posted

技术标签:

【中文标题】类对象上的多线程【英文标题】:Multithreading on Class object 【发布时间】:2013-02-05 00:49:49 【问题描述】:

我收到未处理的异常和访问冲突读取位置错误。但有时它执行得很完美。我是否正确传递了向量和向量迭代器?可能导致错误的原因是什么。

struct DataStructure

    MapSmoother *m1;
    std::vector<Vertex *> v1;
    std::vector<Vertex *>::iterator vit_f;
    std::vector<Vertex *>::iterator vit_e;
    DataStructure() 
        m1 = NULL;
        v1;
        vit_f;
        vit_e;
    
;
DWORD WINAPI thread_fun(void* p)

        DataStructure *input = (DataStructure*)p;
        while ( input->vit_f != input->vit_e ) 
            Vertex *v = *((input->vit_f)++);
            (*(input->m1)).relax(v);
        
        return 0;

int main()

    //Read and encode color to Mesh
    // msmoother is an object
    DataStructure* input = new DataStructure();
    input->m1 = &msmoother;
    for(int i = 0; i < 7; ++i) 
        for(int color = 1; color <= k; color++) 
            std::vector<Vertex *> verList;
          //all the vertices with the same color index will be stored in verList vector
            input->v1 = verList;    //Copied to structure
            std::vector<Vertex *>::iterator vit1 = verList.begin();
            std::vector<Vertex *>::iterator vit2 = verList.end();
            input->vit_f = vit1;
            input->vit_e = vit2;
            HANDLE hThread[50];
            cout << "     Processing for color: " << color << endl;
            for(int j = 0; j < 50; ++j)
                hThread[j] = CreateThread(0,0,(LPTHREAD_START_ROUTINE)&thread_fun,input,0,NULL);
            
            WaitForMultipleObjects(THREAD_COUNT,hThread,TRUE,INFINITE);
            //clear verList vector
            //Close Handles to all threads
        
    

【问题讨论】:

您使用THREAD_COUNT 元素定义了一个HANDLE 数组,但在您的循环中使用了50。THREAD_COUNT 定义在哪里?是大于还是小于 50(或等于)? @dreamlax .. 它是 50 .. 顺便说一句,我没有包括全局变量部分。无论如何 THREAD_COUNT 是 50。 【参考方案1】:

不,您没有正确传递它们。

这段代码:

input->v1 = verList;    //Copied to structure

制作矢量的副本,从外观上看是有意的。由于向量仅包含指向实际数据的指针,因此您只是制作了一堆指针的副本。但是,后续代码:

std::vector<Vertex *>::iterator vit1 = verList.begin();
std::vector<Vertex *>::iterator vit2 = verList.end();
input->vit_f = vit1;
input->vit_e = vit2;

是问题所在。您在 input 对象中设置的迭代器实际上来自本地 verList不是在您的input-&gt;v1 列表中。

试试:

input->vit_f = input->v1.begin();
input->vit_e = input->v1.end();

附录

针对 OP 进行了更新以避免竞争条件和不需要的向量复制。

首先,将DataStructure重新定义为:

struct DataStructure

    MapSmoother *m1;
    std::vector<Vertex *>::iterator first, last
    DataStructure() : m1(NULL) 
;

接下来,将你的线程函数定义为:

DWORD WINAPI thread_fun(void* p)

    DataStructure *input = static_cast<DataStructure*>(p);
    if (input && input->m1)
    
        for (std::vector<Vertex *>::iterator it = input->first
             it != input->last; ++it) 
        
             input->m1->relax(*it);
        
    
    delete input;
    return 0;

最后,调用它:(在你的循环中)

// all the vertices with the same color index will be stored in verList vector
std::vector<Vertex *> verList;
// ... store vector data ...

cout << "     Processing for color: " << color << endl;
HANDLE hThread[50] = NULL;
for(int j = 0; j < _countof(hThread); ++j)

    DataStructure *input= new DataStructure;
    input->first = verList.begin();
    input->last = verList.end();
    input->m1 = &msmoother
    hThread[j] = CreateThread(0,0,(LPTHREAD_START_ROUTINE)&thread_fun,input,0,NULL);

WaitForMultipleObjects(THREAD_COUNT,hThread,TRUE,INFINITE);

或者类似的东西。我只是在网上敲定了这个,所以我不知道它是否可以编译,但希望能给你一个足够体面的想法。每个线程都将自己的一对迭代器放入verList 数组中,并因此进行并发访问。 注意:他们不能修改向量;只使用它。他们获得迭代器的结构由创建者线程分配,但归线程本身所有,线程本身最终负责销毁它。

【讨论】:

@WhozCraig.. 谢谢.. 效果很好.. 你能解释一下吗:input->v1 = verList;我怎样才能将向量传递给线程函数,而不是复制? 对于这个特定的任务,老实说,我会传递一个只有两个迭代器的结构。您要对数据进行分区吗?它会改变我修改答案的方式,这就是我问的原因。关于input-&gt;v1 = verList,您正在制作包含所有项目指针的向量的副本。每个向量的迭代器只对它们来自的向量有效;没有其他人。这是你错误的根源。 @WhozCraig.. 我没有对数据进行分区.. 但是如果我不使用 input->v1 作为迭代器,那么程序可能会再次抛出异常(根据我对之前讨论的理解) 迭代器几乎总是可以复制。所以你可以只传递两个迭代器,然后在线程过程中复制它们,并使用它们而不是结构中传入的那些。如果你愿意,我可以更新答案来证明这一点。 现在我看到了,实际上你的问题比你想象的要多。您将相同的数据结构传递给每个线程 (input),但在每个线程调用之间修改其内容。这实际上是一种竞争条件,而且是一个令人讨厌的条件。我也会尝试解释这一点。但请为我节省一些时间。 verList 是否总是填充 per thread ?如果是这样,那么你不需要两个迭代器,你只需要一个向量和你的 m1 成员。【参考方案2】:

我是 C++ 菜鸟,所以我可能错了,但我认为问题可能出在:

std::vector<Vertex *>::iterator vit1 = verList.begin();
std::vector<Vertex *>::iterator vit2 = verList.end();
input->vit_f = vit1;
input->vit_e = vit2;

您将迭代器传递给verList,而不是传递给已复制到DataStructure 的向量。我想你想要的是:

input->v1 = verList; // copy to structure
input->vit_f = input->v1.begin();
input->vit_e = input->v1.end();

【讨论】:

你不是那个菜鸟=P。这是根本问题。 @WhozCraig:好吧,如果你把我放在一个一端是菜鸟,另一端是经验丰富的 C++ 开发人员的规模上,我会非常喜欢它。 嘿。我曾经认为我处于那种规模的一端,然后我来到了这里,我的上帝我从来没有一天不记得我有多少 知道,所以我就在你身边。 @dreamlax.. 感谢.. 有用的信息 @dreamlax.. 你对此有什么想法吗?输入->v1 = verList;我如何将向量传递给线程函数,而不是复制?

以上是关于类对象上的多线程的主要内容,如果未能解决你的问题,请参考以下文章

Java的多线程

关闭 MFC 对话框时的多线程对象破坏

爬虫中基本的多线程

python通过类的方式创建按线程

java多线程笔记--synchronized类,对象,方法,代码块

Java中的多线程