在线程之间共享一个类
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
,而我预计两者之间会有更多的变化。
main.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。 (尽管据我所知,这对于这种特定情况并不重要。) 您有什么理由不使用<thread>
的 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 <vector>
在我的 main.cpp 文件中没有意义,因为 Vector.hpp 包含在 main.cpp 中。
@user54952820 "这只是给了我一大堆错误" - 你必须比这更具体。实际错误是什么?
@user54952820 <vector>
定义标准的std::vector
容器,而Vector.hpp
定义您的自定义Vector
类。两个单独的班级。 Vector
是否在内部使用 std::vector
并不重要(它没有)。 main()
想要使用std::vector
,所以它应该使用#include <vector>
。如果<vector>
之前已经是#include
,那完全可以
我只是不明白你在这种情况下使用std::vector
。以上是关于在线程之间共享一个类的主要内容,如果未能解决你的问题,请参考以下文章