在线程之间共享一个类

Posted

技术标签:

【中文标题】在线程之间共享一个类【英文标题】:Sharing a class between threads 【发布时间】:2020-02-25 01:14:49 【问题描述】:

我有一个名为“Vector”的类,默认情况下它包含 10.000 个元素,这些元素在任何时候都必须具有相同的值。这个类已经过测试并且可以工作。因此,我使用类中的方法 setAndTest() 来设置所有元素的值,然后立即检查 Vector 对象是否一致(所有向量元素都具有相同的值)。

在一个新文件“main.cpp”中,我创建了两个函数:writer()main()writer() 创建用户定义数量的 writer 线程(介于 1 和 100 之间),每个线程都有自己唯一的 id。每个 writer 每秒将共享 Vector 对象设置和测试为其 id。如果编写器在共享 Vector 对象中检测到不一致,setAndTest() 将返回 false 并应打印以下错误消息:Error with thread #id 然而,在 99% 的情况下,它会输出 Success with thread #id,而我预计两者之间会有更多的变化。

ma​​in.cpp 文件中包含的头文件:

#include <iostream>
#include "Vector.hpp"
#include <pthread.h>
#include <unistd.h>
using namespace std;

向量对象和 writer() 函数:

Vector VecObj;  //The Vector object (Defined in global scope)

void* writer(void *threadid)

    int threadid_ = *(int *)(threadid); 

    if(VecObj.setAndTest(threadid_))
    
        std::cout << "\nSuccess with thread " << threadid_ << endl;
    else
    
        std::cout << "\nError with thread " << threadid_ << endl;
    

    return NULL;

主要功能:

int main()

    start:
    int numOfThreads = 1;
    std::cout << "Enter amount of threads (must be between 1 & 100): ";
    std::cin >> numOfThreads;
    if(0 < numOfThreads && numOfThreads <= 100)
        std::cout << "You entered " << numOfThreads << " threads" << endl;
    else
        std::cout << "Amount of threads must be between 1 & 100" << endl;
        goto start;
    

    pthread_t threadcreator[numOfThreads];

    for(int i = 0; i < numOfThreads; i++)
        pthread_create(&threadcreator[i], NULL, writer, &i);
        sleep(1);
    

    for(int i = 0; i < numOfThreads; i++)
        pthread_join(threadcreator[i], NULL);
    


矢量类(Vector.hpp):

#ifndef VECTOR_HPP_
#define VECTOR_HPP_
#include <pthread.h>
using namespace std;

//=======================================================
// Class: Vector
// contains a size_-size vector of integers.
// Use the function setAndTest to set all elements
// of the vector to a certain value and then test that
// the value is indeed correctly set
//=======================================================
class Vector

public:
   Vector(unsigned int size = 10000) : size_(size)
      
         vector_ = new int[size_];
         set(0);
      

   ~Vector()
      
         delete[] vector_;
      

   bool setAndTest(int n)
      
         set(n);
         return test(n);
      

private:
   void set(int n)
      
         for(unsigned int i=0; i<size_; i++) vector_[i] = n;
      

   bool test(int n)
      
         for(unsigned int i=0; i<size_; i++) if(vector_[i] != n) return false;
         return true;
      

   int*           vector_;
   unsigned int   size_;

;

#endif

【问题讨论】:

"这个类已经过测试并且可以工作。":这个类明显违反了rule-of-three。 (尽管据我所知,这对于这种特定情况并不重要。) 您有什么理由不使用&lt;thread&gt; 的 C++11 线程工具吗? 【参考方案1】:

您正在向每个线程传递一个指向同一个int 变量的指针。该变量在每次循环迭代时都会改变值。 writer() 期望收到与 pthread_create() 相同的 int 值,但即使使用 sleep() 调用,您的代码也不能保证这一点。

要正确传递int,请传递实际的int 值本身而不是指向int 的指针,例如:

#include <iostream>
#include <vector>
#include <cstdint>
#include <pthread.h>
#include "Vector.hpp"

Vector VecObj;

void* writer(void *arg)

    int threadid_ = static_cast<int>(reinterpret_cast<intptr_t>(arg));

    if (VecObj.setAndTest(threadid_))
    
        std::cout << "\nSuccess with thread " << threadid_ << std::endl;
    
    else
    
        std::cout << "\nError with thread " << threadid_ << std::endl;
    

    return NULL;


int main()

    int numOfThreads = 0;

    do 
        std::cout << "Enter amount of threads (must be between 1 & 100): ";
        std::cin >> numOfThreads;
        if (0 < numOfThreads && numOfThreads <= 100)
            std::cout << "You entered " << numOfThreads << " threads" << std::endl;
            break;
        
        std::cout << "Amount of threads must be between 1 & 100" << std::endl;
    
    while (true);

    std::vector<pthread_t> threadcreator(numOfThreads);

    for(int i = 0; i < numOfThreads; i++)
        pthread_create(&threadcreator[i], NULL, writer, reinterpret_cast<void*>(i));
    

    for(int i = 0; i < numOfThreads; i++)
        pthread_join(threadcreator[i], NULL);
    

    return 0;

如果你真的想使用int*指针,那么你将不得不为每个线程分配一个单独的int,例如:

#include <iostream>
#include <vector>
#include <pthread.h>
#include "Vector.hpp"

Vector VecObj;

void* writer(void *arg)

    int threadid_ = *static_cast<int*>(arg);

    if (VecObj.setAndTest(threadid_))
    
        std::cout << "\nSuccess with thread " << threadid_ << std::endl;
    
    else
    
        std::cout << "\nError with thread " << threadid_ << std::endl;
    

    return NULL;


int main()

    int numOfThreads = 0;

    do 
        std::cout << "Enter amount of threads (must be between 1 & 100): ";
        std::cin >> numOfThreads;
        if (0 < numOfThreads && numOfThreads <= 100)
            std::cout << "You entered " << numOfThreads << " threads" << std::endl;
            break;
        
        std::cout << "Amount of threads must be between 1 & 100" << std::endl;
    
    while (true);

    std::vector<pthread_t> threadcreator(numOfThreads);
    std::vector<int> threadids(numOfThreads);

    for(int i = 0; i < numOfThreads; i++)
        threadids[i] = i;
        pthread_create(&threadcreator[i], NULL, writer, &threadids[i]);
    

    for(int i = 0; i < numOfThreads; i++)
        pthread_join(threadcreator[i], NULL);
    

    return 0;

或者,如果您真的想将 int* 指针传递给单个 int,请使用 std::conditional_variable 或其他可等待信号以确保每个线程在允许循环之前实际捕获了 int 值改变它的值,例如:

#include <iostream>
#include <vector>
#include <conditional_variable>
#include <mutex>
#include "Vector.hpp"
#include <pthread.h>

Vector VecObj;
std::condition_variable cv;
std::mutex cv_m;
bool captured = false;

void* writer(void *arg)

    int threadid_;

    
    std::lock_guard<std::mutex> lk(cv_m);
    threadid_ = *static_cast<int*>(arg);
    captured = true;
    
    cv.notify_one();

    if (VecObj.setAndTest(threadid_))
    
        std::cout << "\nSuccess with thread " << threadid_ << std::endl;
    
    else
    
        std::cout << "\nError with thread " << threadid_ << std::endl;
    

    return NULL;


int main()

    int numOfThreads = 0;

    do 
        std::cout << "Enter amount of threads (must be between 1 & 100): ";
        std::cin >> numOfThreads;
        if (0 < numOfThreads && numOfThreads <= 100)
            std::cout << "You entered " << numOfThreads << " threads" << std::endl;
            break;
        
        std::cout << "Amount of threads must be between 1 & 100" << std::endl;
    
    while (true);

    std::vector<pthread_t> threadcreator(numOfThreads);

    for(int i = 0; i < numOfThreads; i++)
        std::unique_lock<std::mutex> lk(cv_m);
        captured = false;
        pthread_create(&threadcreator[i], NULL, writer, &i);
        cv.wait(lk, []() return captured; );
    

    for(int i = 0; i < numOfThreads; i++)
        pthread_join(threadcreator[i], NULL);
    

    return 0;

更新:哦,现在我看到了另一个主要问题。您有多个线程在没有同步的情况下对内存中的单个 Vector 对象进行写入和读取。这样做是不安全的。当一个线程正在读取Vector 数组中的元素时,另一个线程可以将新值写入同一元素,并且不能保证该元素在两个操作中保持一致。您必须同步对 Vector 对象的访问,因为它在多个线程之间共享,例如:

...
#include <mutex>
...

Vector VecObj;
std::mutex vec_m;
...

void* writer(void *threadid)

    int threadid_ = ...;
    bool testResult;

    
    std::lock_guard lk(vec_m);
    testResult = VecObj.setAndTest(threadid_);
    

    if (testResult)
    
        std::cout << "\nSuccess with thread " << threadid_ << std::endl;
    
    else
    
        std::cout << "\nError with thread " << threadid_ << std::endl;
    

    return NULL;


...

【讨论】:

这并没有真正的帮助。它只是给了我一大堆错误。 另外,#include &lt;vector&gt; 在我的 main.cpp 文件中没有意义,因为 Vector.hpp 包含在 main.cpp 中。 @user54952820 "这只是给了我一大堆错误" - 你必须比这更具体。实际错误是什么? @user54952820 &lt;vector&gt; 定义标准的std::vector 容器,而Vector.hpp 定义您的自定义Vector 类。两个单独的班级。 Vector 是否在内部使用 std::vector 并不重要(它没有)。 main() 想要使用std::vector,所以它应该使用#include &lt;vector&gt;。如果&lt;vector&gt; 之前已经是#include,那完全可以 我只是不明白你在这种情况下使用std::vector

以上是关于在线程之间共享一个类的主要内容,如果未能解决你的问题,请参考以下文章

在线程之间共享资源,在不同的Java版本中使用不同的行为

多线程之间通讯

java多线程基础

线程有有序性和可见性

JAVA多线程之间共享数据BlockingQueue介绍

同一线程中类的所有实例中的类的共享数据成员