简体   繁体   中英

How to access class data members in a thread without passing them as arguments?

I am initializing a vector in a class using 4 threads by passing arguments to threads:

//main.cpp
#include "stdafx.h"
#include <stdlib.h>
#include <vector>
#include "class.h"

using namespace std;
int main()
{
    myCLASS* classObject = new myCLASS();
    classObject->classMemberFunction();
    return 0;
}

and

//class.h
#include "stdafx.h"
#include <vector>
#include <mutex>

#ifndef SLIC_H
#define SLIC_H

class myCLASS
{
protected:
    std::vector<int> cluster;
    std::mutex cluster_mutex;
    int iterations;
    void clearData();

public:
    myCLASS();
    /* Class copy constructor. */
    myCLASS(const myCLASS& othermyCLASS);

    /* Class destructor. */
    virtual ~myCLASS();

    void classMemberFunction();
    //creating threads function
    void thread2(std::vector<int> *cluster, int *iterations);
    void thread3(std::vector<int> *cluster, int *iterations);
    void thread4(std::vector<int> *cluster, int *iterations);
};
#endif

and

//class.cpp
#include "stdafx.h"
#include "class.h"
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
using namespace std;

myCLASS::myCLASS()
{
    clearData();
}

myCLASS::myCLASS(const myCLASS& othermyCLASS)
{
}

myCLASS::~myCLASS()
{
    clearData();
}

void myCLASS::clearData()
{
    /* Erase all matrices' elements. */
    this->cluster.clear();
}
void myCLASS::classMemberFunction(void)
{
    this->iterations = 1000;
    thread t2(&myCLASS::thread2, *this, &cluster, &iterations);
    thread t3(&myCLASS::thread3, *this, &cluster, &iterations);
    thread t4(&myCLASS::thread4, *this, &cluster, &iterations);

    //main thread===================================================
    for (int n = 0; n < iterations / 4; ++n)
    {
        cluster.push_back(-1);
    }
    t2.join();
    t3.join();
    t4.join();
    cout << cluster.size() << endl;
    system("PAUSE");
}

void myCLASS::thread2(std::vector<int> *cluster, int *iterations)
{
    cluster_mutex.lock();
    for (int n = 0; n < (*iterations) / 4; ++n)
    {
        cluster->push_back(-1);
    }
    cluster_mutex.unlock();
}

void myCLASS::thread3(std::vector<int> *cluster, int *iterations)
{
    cluster_mutex.lock();
    for (int n = 0; n < (*iterations) / 4; ++n)
    {
        cluster->push_back(-1);
    }
    cluster_mutex.unlock();
}

void myCLASS::thread4(std::vector<int> *cluster, int *iterations)
{
    cluster_mutex.lock();
    for (int n = 0; n < (*iterations) / 4; ++n)
    {
        cluster->push_back(-1);
    }
    cluster_mutex.unlock();
}

the thing is I don't want to pass those two arguments to threads. I want threads to explicitly access data members iterations and cluster and manipulate them by taking void as arguments !

Threading is difficult and there's a lot going on here, perhaps too much to address with a single post. I think it's also best to focus on general style here rather than some of the correctness issues. In my experience, correctness comes with a better code layout. Some of the ways it can be improved are:

  • Increase concurrency: all of the work being done is protected by mutexes so only one thread can actually work at any given time. Since extra work is done to lock the mutexes and thread-hop, this implementation will actually be slower than a non-threaded version.

  • Reduce duplicated code. No need to have a different function for each thread; just call your thread n function multiple times with different arguments.

  • Use of classes. your class data members should be private, not protected. Also, you have a data member (iterations) that is used as a constant. Mark it const and set it in the constructor initializer list: myCLASS::myCLASS() : iterations(1000); .

  • Your thread functions are members, so they have access to all private data members. ie No need to pass cluster and iterations when all threads can read them.

  • Eliminate use of pointers: In modern C++, there is almost never a reason to call new on a class or pass around raw pointers unless you know what you're doing. You can pass by value or reference instead, or std::shared_ptr or its ilk if needed.

  • Use stl algorithms and iterators. Generally, your code will be better all-around if you can reuse code that others have written. It has been reviewed and used many times so it will be bug-free and efficient. Plus, others are familiar with them so it will be readable. Iterators allow you controlled access to your data structures and allow you to use the stl algorithms far more effectively.

for example, let's say you only have one thread. Your loop to populate the vector would be :

for (int n = 0; n < *iterations; ++n) {
            cluster->push_back(-1);
}

which could be written as:

 cluster.resize(iterations); // preallocate space
 std::fill(begin(cluster), end(cluster), -1);

Once you look at the problem this way, you can split it up even further. You want to split the work over many threads, and you have a function that does the work for a given range, so it's natural to give each thread a different range. Here's a single-threaded version of that idea:

cluster.resize(iterations);

auto segmentBegin = begin(cluster);
auto segmentEnd = next(segmentBegin, 250);
std::fill(segmentBegin, segmentEnd, -1);

segmentBegin = segmentEnd;
std::advance(segmentEnd, 250);
std::fill(segmentBegin, segmentEnd, -1);

Each fill is now working on a different part of the vector so if you put each fill on a different thread, you will not have concurrent access to any one memory address.. which means no mutexes are needed!

When moving to multiple threads, I would recommend something like this lambda

auto const fillfunc = [](std::vector<int>::iterator const mybegin,
                         std::vector<int>::iterator const myend) -> void 

{
        std::fill(mybegin, myend, -1);
}; 

to glue it all together so you can just pass fillfunc and a couple of iterators to the thread constructor without having to repeat the -1 constant.

Having said all that, this might also be a good use of std::async

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM