【问题标题】:Passing arguments with struct to pthread [closed]将带有结构的参数传递给pthread [关闭]
【发布时间】:2019-08-08 07:32:53
【问题描述】:

如下所示,functionA 将传递一些参数并创建一个线程来执行一些计算并将结果存储到 ResultPool(全局)中以供以后使用。 functionA 将被调用几次,每次它传递不同的参数并创建一个新线程。所有的thread_id都会保存在全局变量中,在执行结束时,会从ThreadIdPool中取出thread_id并检查线程是否完成,然后从中输出结果结果池。下面的示例代码中省略了线程状态检查和输出结果。

我下面的代码是否是线程安全的,尤其是对于那些共享数据?我应该添加什么来防止灾难性故障吗?请指教

IntS threadCnt;
struct ThreadData
{
  int        td_tnum;
  float      td_Freq;
  bool       td_enablePlots; 
  int        td_ifBin;
  int        td_RAT;
 };
 typedef struct ThreadData structThreadDt;
 void *thread_A(void *td);
 map<int, float> ResultPool;
 map<int, pthread_t> ThreadIdPool;
 pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
 pthread_t thread_id[10];

 void FunctionA(int tnum, float msrFrequency, bool enablePlots)
 {
    //Pass the value to the variables.
   int ifBin;
   int RAT;

  /*
    Some calculation here and the results are assigned to ifBin and RAT
  */

  structThreadDt *td;     
  td =(structThreadDt *)malloc(sizeof(structThreadDt));
  td->td_tnum = tnum;
  td->td_Freq = msrFrequency;
  td->td_enablePlots = enablePlots; 
  td->td_ifBin = ifBin;
  td->td_RAT = RAT;

   threadCnt = threadCnt+1;
   pthread_create(&thread_id[threadCnt], NULL, thread_A, (void*) td);    

   //Store the thread id to be check for the status later.   
   ThreadIdPool[tnum]=thread_id[threadCnt]; 
  }

void* thread_A(void* td)
{
  int   ifBin; 
  int   RAT;

  BoolS enablePlots;
  FloatS msrFrequency;
  IntS tnum;   

  structThreadDt *tds;
  tds=(structThreadDt*)td;        
  enablePlots = tds->td_enablePlots;
  msrFrequency = tds->td_Freq;
  tnum = tds->td_tnum;
  ifBin = tds->td_ifBin ;
  RAT = tds->td_RAT;       

  /*
    Do some calculation here with those ifBIN, RAT, TNUM and frequency.

  */

  //Store the result to shared variable with mutex lock
  pthread_mutex_lock( &mutex2 );
  ResultPool[tnum] = results;
  pthread_mutex_unlock( &mutex2 );

  free(tds);

  return NULL;

 }

【问题讨论】:

  • 在 C++ 程序中使用mallocfree 有什么原因吗?为什么不使用std::thread(这会简化很多事情)?如果你有 ThreadIdPool 映射,为什么你需要 thread_id 数组(你没有任何边界检查)?
  • 不幸的是,我使用的是不支持 std::thread 的旧版 C++。我确实在执行结束时检查了线程完成情况,这发生在另一段代码中,我没有在这里显示。

标签: c++ pthreads


【解决方案1】:

我会改变的事情(试图防止失败):

  • 如果您有足够新的 C++ 版本可用,请使用 std::thread 和 std::mutex 代替 pthread
  • 不要使用 malloc/free,而是使用 std::unique_ptr / std::shared_ptr 等(这样可能更安全)
  • 确保 std::maps 只有在其互斥锁被锁定时才能访问(例如,创建一个具有更改映射功能的类,以便确保所有访问都得到适当保护)
  • 如果数据只能从任何地方访问,那么将共享数据作为全局变量可能会成为问题,因此我会尝试将它们移出全局范围并使用依赖注入或类似机制。 (使用 std::thread 等应该会更容易)

我不知道您要解决的确切问题是什么,但完全放弃手动线程管理并改用 std::future 和 std::async 甚至可能是有意义的。

【讨论】:

  • 我很想使用更简单的std::thread。不幸的是,我使用的是旧版本的 C++,而且我没有能力升级它。基本上,我上面的代码试图将耗时的计算转移到线程中。并且一旦计算完成,存储结果并在父进程中输出结果。
  • 您的编译器/库已经超过 8 年了?
  • 是的,确实,我没有选择使用后一个版本。
【解决方案2】:

从发布的代码中,我看不出需要thread_id,但如果您出于某种原因需要它,那么您应该修复threadCnt。现在第一次插入时它不是以 0 开头的。

ResultPool 可以从thread_A 安全地访问,但必须从遍历它的线程中正确完成以获取结果。如果functionA要被不同的线程调用,则需要将其中的所有全局变量互斥。

如果您没有std::lock_guard,那么我建议您为互斥锁实现自己的lock_guard,而不是锁定/解锁。

如果您决定使用 c++11,示例代码。

#include <iostream>
#include <future>
#include <thread>
#include <vector>

// Dummy
using ResultType = uint64_t;

std::future<ResultType>
FunctionA(int tnum, float msrFrequency, bool enablePlots) {
  return std::async(std::launch::async,
                    [tnum,msrFrequency,enablePlots] () -> ResultType {
                      // Dummy Calculation
                      std::cout << "Executing ..." << std::this_thread::get_id() << std::endl;
                      return tnum + msrFrequency + enablePlots;
                    });
}


int main () {
  std::vector<std::future<ResultType>> results;
  results.emplace_back(FunctionA(1,2,3));
  results.emplace_back(FunctionA(4,5,6));
  results.emplace_back(FunctionA(7,8,9));

  // Check results
  for (auto &r : results) {
    if (r.valid()) {
      std::cout << "result is available: " << r.get() << std::endl;
    }
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-09
    • 1970-01-01
    • 1970-01-01
    • 2013-03-29
    • 1970-01-01
    • 2019-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多