使用 pthread_create 时出现“分段错误(核心转储)”

Posted

技术标签:

【中文标题】使用 pthread_create 时出现“分段错误(核心转储)”【英文标题】:"Segmentation fault (core dumped)" while using pthread_create 【发布时间】:2017-12-17 22:41:44 【问题描述】:

所以我遇到了一个问题:当我尝试创建最后一个线程时,它总是说核心已转储。如果我写来创建 5 个或 2 个线程都没关系。这是我的代码: UPD:现在我不能做超过 3 个线程并且线程不做我想让他们做的功能(消费和生产)

UPD_2:现在我发出这样的消息:在抛出一个 'terminate 递归调用实例后调用终止 递归调用终止 中止(核心转储)

 #include<cstdlib>
#include <iostream>
#include <string>
#include <mutex>
#include <pthread.h>
#include <condition_variable>

#define NUM_THREADS 4

using namespace std;

struct thread_data

   int  thread_id;
   int  repeat;
;


 class our_monitor
    private:
        int buffer[100];
        mutex m;
        int n = 0, lo = 0, hi = 0;
        condition_variable in,out;
        unique_lock<mutex> lk;

    public:
        our_monitor():lk(m)
        

        
        void insert(int val, int repeat)
        
            in.wait(lk, [&]return n <= 100-repeat;);
            for(int i=0; i<repeat; i++)
            
                buffer[hi] = val;
                hi = (hi + 1) % 100;        //ring buffer
                n = n +1;         //one more item in buffer
            
            lk.unlock();
            out.notify_one();
        

        int remove(int repeat)
        
            out.wait(lk, [&]return n >= repeat;);
            int val;
            for(int i=0; i<repeat; i++)
            
                val = buffer[lo];
                lo = (lo + 1) % 100;
                n -= 1;
            
            lk.unlock();
            in.notify_one();
            return val;
        
;

our_monitor mon;

void* produce(void *threadarg)

    struct thread_data *my_data;
    my_data = (struct thread_data *) threadarg;
    cout<<"IN produce after paramiters"<< my_data->repeat<<endl;
    int item;
    item = rand()%100 + 1;
    mon.insert(item, my_data->repeat);
    cout<< "Item: "<< item << " Was prodused by thread:"<< my_data->thread_id << endl;


void* consume(void *threadarg)
    
        struct thread_data *my_data;
        my_data = (struct thread_data *) threadarg;
        cout<<"IN consume after paramiters"<< my_data->repeat<<endl;
        int item;
        item = mon.remove(my_data->repeat);
        if(item) cout<< "Item: "<< item << " Was consumed by thread:"<< my_data->thread_id << endl;
    

int main()

    our_monitor *mon = new our_monitor();
    pthread_t threads[NUM_THREADS];
    thread_data td[NUM_THREADS];
    int rc;
    int i;

    for( i = 0; i < NUM_THREADS; i++ )
    
        td[i].thread_id = i;
        td[i].repeat = rand()%5 + 1;
        if(i % 2 == 0)
        
            cout << "main() : creating produce thread, " << i << endl;
            rc = pthread_create(&threads[i], NULL, produce, (void*) &td[i]);

            if (rc)
            
                cout << "Error:unable to create thread," << rc << endl;
                exit(-1);
            
         else
        
            cout << "main() : creating consume thread, " << i << endl;
            rc = pthread_create(&threads[i], NULL, consume, (void *)&td[i]);

            if (rc)
            
                cout << "Error:unable to create thread," << rc << endl;
                exit(-1);
            
        
    
    pthread_join(threads[0], NULL);
    pthread_join(threads[1], NULL);
    pthread_join(threads[2], NULL);
    //pthread_exit(NULL);


UPD:现在我不能执行超过 3 个线程,并且线程不执行我希望它们执行的功能(消费和生产)

UPD_2:现在我有这样的消息:在抛出一个递归调用的 'terminate 实例后调用终止 递归调用终止 中止(核心转储)

【问题讨论】:

你怎么知道它是在main 而不是线程进程之一? 你能解释一下,produceconsume指向哪些函数? 我编辑我的问题,有完整的代码 使用 std::thread 代替 pthreads。 没用 【参考方案1】:

来自 cppref 关于 std::condition_variable.wait(...)

"如果lock.mutex()没有被当前锁住就调用这个函数 线程是未定义的行为。”

http://en.cppreference.com/w/cpp/thread/condition_variable/wait

不幸的是,程序并没有在第 47 行崩溃,而是在第 55 行,您解锁了未锁定的锁。

当您进入您的功能时锁定锁。我已经快速检查了你的其余逻辑,我有 85% 的把握确定它没有问题。

虽然我有你在这里,但这并不是绝对必要的,但这是一种很好的做法。 std::lock_guard 和 std::unique_lock 在进入作用域时自动锁定互斥锁,在离开作用域时将其解锁。这有助于简化异常处理和奇怪的函数返回。我建议您摆脱 lk 作为成员变量,而将其用作作用域局部变量。

    void insert(int val, int repeat)
    
         // Scoped. Somewhat pedantic in this case, but it's always best to signal after the mutex is unlocked
            std::unique_lock<std::mutex> lk(m);
            in.wait(lk, [&]return n <= 100-repeat;);
            for(int i=0; i<repeat; i++)
            
                buffer[hi] = val;
                hi = (hi + 1) % 100;        //ring buffer
                n = n +1;         //one more item in buffer
            
        
        out.notify_one();
    

好的,现在是最后一期。生产者/消费者最酷的地方在于我们可以同时生产和消费。但是,我们只是锁定了我们的函数,所以这不再可能。您现在可以做的是将您的条件锁定/等待/解锁/工作/信号移入 for 循环

在伪代码中:

// produce:
while (true)

    
        unique_lock lk(m)
        wait(m, predicate)
    
    produce 1
    signal

这相当于使用信号量(C++'11 stl 没有,但您可以轻松地制作自己的,如上所示。)

// produce:
semaphore in(100);
semaphore out(0);
while (true)

    in.down(1)  // Subtracts 1 from in.count. Blocks when in.count == 0 (meaning the buffer is full)
    produce 1
    out.up(1)   // Adds 1 to out.count

【讨论】:

【参考方案2】:

main 结束时,td 超出范围并不再存在。但是您将指针传递给线程。您需要确保td 继续存在,只要任何线程可能正在使用它。

【讨论】:

我该怎么做? @MaxPan 一种可能的方式:加入main末尾的线程,这样在td超出范围时线程已经结束。 一种常见的模式是分配一个结构来将数据传递给new的线程。将您从new 获得的指针传递给线程。然后线程读取数据后,就可以delete了。但是,如果您需要从线程传回数据,那将不起作用。

以上是关于使用 pthread_create 时出现“分段错误(核心转储)”的主要内容,如果未能解决你的问题,请参考以下文章

在 TCP 服务器中使用 pthread_create 时出现错误 11

Ubuntu使用多线程cmake时出现undefined reference to `pthread_create'

Debian下undefined reference to ‘pthread_create’问题解决

[Android]异常10-java.lang.OutOfMemoryError pthread_create (1040KB stack) failed: Try again

将音频流写入循环缓冲区但分段错误读取值

如何从循环外部杀死无限循环中的pthread?