将带有结构的参数传递给 pthread

Passing arguments with struct to pthread

本文关键字:参数传递 pthread 结构      更新时间:2023-10-16

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

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

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;
}

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

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

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

从发布的代码来看,我认为不需要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;
}
}
}