C++ std::bad_function_call 与 Segmentation Fault 同时出现
本帖最后由 hellomyprogram 于 2023-8-4 07:15 编辑在我的代码中,如果保留 threads.cpp 第 46 行的 if (function) ,那么我的程序会突然无响应。
而如果删除的话,我的代码会报 Segmentation Fault 和 std::bad_function_call ,但是它们出现似乎是随机的,有的时候有,有的时候没有。
Segmentation Fault 错误出现在 main.cpp 的第 17 行。 std::bad_function_call 出现在 threads.cpp 的第 45 行。
请问这是为什么?又怎么解决?
--- 已解决 ---
问题出自内存泄漏,在 DistributeThread::run 下调用了 sleep 函数,但是 sleep 函数只接受整数,因此我输入的小数都被整型化为 0 ,因此 DistributeThread “疯了”,乱发任务,导致内存泄漏,在崩溃时刻,线程里的任务队列已经积攒到百万数量级。 这种情况通常发生在多线程代码中,涉及了竞态条件(race condition)或者内存访问错误。Segmenation Fault 表示你的程序试图访问了无效的内存地址,而 std::bad_function_call 则表示你尝试调用一个空的 std::function 对象。
解决这个问题的步骤如下:
1. 调试 Segmentation Fault:
· 确保你没有越界访问数组或者指针。
· 确保没有在使用已释放的内存。
· 确保没有使用空指针。
· 使用工具如valgrind来检查内存错误。
2. 调试 std::bad_function_call:
· 确保在调用 std::function 之前,该对象已经被正确地初始化。
· 确保你没有在多个线程中同时修改或调用同一个 std::function 对象,可能需要使用互斥锁来保护。
· 如果是从其他线程调用的 std::function,确保在调用之前该函数对象不会被销毁。
3. 处理竞态条件:
· 使用互斥锁(mutex)来保护共享数据,确保每个线程在访问共享数据之前先锁定互斥锁,在访问完毕后解锁。
· 考虑使用原子操作来进行简单的线程安全操作。
4. 使用调试工具:
· 使用调试器(如 GDB)来逐步调试程序,查找问题所在。
· 使用线程检测工具(如 Helgrind)来检测多线程代码中的问题。
5. 编写更健壮的代码:
· 仔细设计多线程架构,避免竞态条件和死锁。
· 使用智能指针等 RAII 技术来管理资源,避免内存泄漏。
在定位问题时,可以根据错误出现的条件和频率来排查。如果问题确实难以找到,可能需要更详细的代码和错误信息来进行深入分析。 问题分析
根据提供的代码文件和问题描述,出现 Segmentation Fault 和 std::bad_function_call 错误的位置分别在 main.cpp 的第 17 行和 threads.cpp 的第 45 行。这些错误似乎是随机出现的。
由于没有提供完整的代码,我无法直接定位问题的具体原因。但是可以给出一些可能导致这些错误的常见原因和解决方法。
解决方案
1. Segmentation Fault 错误:
- 检查第 17 行代码附近的指针操作,确保指针有效,并且没有被释放、空指针解引用等问题。
- 检查是否存在数组越界的情况,确保数组访问不超过合法范围。
- 使用合适的内存管理技术,如智能指针(std::shared_ptr、std::unique_ptr)来避免内存泄漏和悬挂指针等问题。
- 如果有多线程代码,请确保在访问共享资源时正确地进行同步,以避免竞态条件等问题。
2. std::bad_function_call 错误:
- 检查第 45 行代码附近的函数对象使用,确保在调用函数对象之前,已经将有效的函数对象绑定到它上面。
- 在使用函数对象之前,可以使用条件语句或者std::function::target来检查函数对象是否为空,避免调用无效的函数对象。
- 确保函数签名匹配,避免调用时参数类型不匹配或者返回值类型不一致。
3. 除了以上的常见问题,还可能存在其他与特定代码相关的问题。这种情况下,需要仔细检查相关代码,进行逐行调试并使用调试器来跟踪程序执行过程,以找出错误发生的具体原因。
请注意,由于我无法直接查看并修改你上传的代码,以上解决方案只是根据常见问题给出的一般性建议。如果你能提供更多关于问题的上下文信息或相关的代码片段,我可以尝试提供更具体的帮助。
如果回答对你有帮助,请给我一个最佳答案!{:10_254:}{:10_254:}{:10_254:}
完整代码如下:
// main.cpp
#include <SFML/Graphics.hpp>
#include "threads.h"
DistributeThread threads;
class Main
{
public:
double view_direction = {0, 0};
double player_position = {0, 0, 0};
sf::RenderWindow *window = nullptr;
sf::RenderWindow *window_log = nullptr;
sf::Event event;
void control()
{
while (this->window->pollEvent(event))
{
switch (event.type)
{
case sf::Event::KeyPressed:
if (event.key.control)
{
switch (event.key.code)
{
case sf::Keyboard::L:
if (this->window_log == nullptr)
{
this->window_log->setVisible(true);
}
break;
};
};
break;
case sf::Event::Closed:
this->window->close();
threads.stop();
break;
};
};
};
void init()
{
this->window = new sf::RenderWindow(sf::VideoMode(1000, 1000), "Minecraft for C");
this->window_log = new sf::RenderWindow(sf::VideoMode(1000, 1000), "Minecraft for C");
this->window_log->setVisible(false);
};
};
int main()
{
Main system;
threads.work("Control", std::bind(Main::init, &system));
threads.repeat_work("Control", 50, std::bind(Main::control, &system));
if (threads.start())
{
threads.join();
};
return 0;
};
// math.cpp
#include <cmath>
#include "math.h"
#include "constants.hpp"
double radian(const double theta){
return theta * (constants::pi / 180);
};
Matrix::Matrix(const Matrix &item) : Matrix(item.dimensions, item.values)
{};
Matrix::Matrix(Matrix &&item)
{
this->dimensions = item.dimensions;
this->dimensions = item.dimensions;
this->values = item.values;
item.values = nullptr;
};
Matrix::Matrix(const unsigned short dimensions)
{
this->dimensions = dimensions;
this->dimensions = dimensions;
this->values = new double * dimensions]();
};
Matrix::Matrix(const unsigned short dimensions, const double *values) : Matrix(dimensions)
{
for (unsigned int ptr_offset = 0; ptr_offset < dimensions * dimensions; ptr_offset++)
{
*(this->values + ptr_offset) = *(values + ptr_offset);
};
};
Matrix::~Matrix()
{
if (this->values != nullptr)
{
delete[] this->values;
};
};
Matrix Matrix::operator+(const Matrix &other) const
{
if (this->dimensions != other.dimensions || this->dimensions != other.dimensions)
{
throw errors::MatrixDimensionError();
};
Matrix result(*this);
for (unsigned int ptr_offset = 0; ptr_offset < this->dimensions * this->dimensions; ptr_offset++)
{
*(result.values + ptr_offset) += *(other.values + ptr_offset);
};
return result;
};
Matrix Matrix::operator+(const double other) const
{
Matrix result(*this);
for (unsigned int ptr_offset = 0; ptr_offset < this->dimensions * this->dimensions; ptr_offset++)
{
*(result.values + ptr_offset) += other;
};
return result;
};
Matrix Matrix::operator-() const
{
Matrix result(*this);
for (unsigned int ptr_offset = 0; ptr_offset < this->dimensions * this->dimensions; ptr_offset++)
{
*(result.values + ptr_offset) += -*(result.values + ptr_offset);
};
return result;
};
Matrix Matrix::operator-(const Matrix &other) const
{
Matrix reversed = -other;
return *this + reversed;
};
Matrix Matrix::operator-(const double other) const
{
return *this + -other;
};
Matrix Matrix::operator*(const Matrix &other) const
{
if (this->dimensions != other.dimensions)
{
throw errors::MatrixDimensionError();
};
unsigned short result_dimensions = {this->dimensions, other.dimensions};
Matrix result(result_dimensions);
int result_ptr_offset, this_ptr_offset, other_ptr_offset;
for (short result_row = 0; result_row < result_dimensions; result_row++)
{
for (short result_column = 0; result_column < result_dimensions; result_column++)
{
result_ptr_offset = result_row * result_dimensions + result_column;
for (short index = 0; index < this->dimensions; index++)
{
this_ptr_offset = result_row * this->dimensions + index;
other_ptr_offset = index * other.dimensions + result_column;
*(result.values + result_ptr_offset) += *(this->values + this_ptr_offset) * *(other.values + other_ptr_offset);
};
};
};
return result;
};
Vector Matrix::operator*(const Vector &other) const
{
unsigned short vector_matrix_dimensions = {other.dimensions, 1};
Matrix vector_matrix(vector_matrix_dimensions, other.values);
Matrix result_matrix = *this * vector_matrix;
Vector result = Vector(result_matrix.dimensions, result_matrix.values);
return result;
};
Matrix Matrix::operator*(const double other) const
{
Matrix result(*this);
for (unsigned int ptr_offset = 0; ptr_offset < this->dimensions * this->dimensions; ptr_offset++)
{
*(result.values + ptr_offset) *= other;
};
return result;
};
Matrix Matrix::operator/(const double other) const
{
return *this * (1.0 / other);
};
Matrix Matrix::transpose() const
{
Matrix result(this->dimensions);
unsigned short row, column;
for (unsigned int ptr_offset = 0; ptr_offset < this->dimensions * this->dimensions; ptr_offset++)
{
row = ptr_offset / this->dimensions;
column = ptr_offset % this->dimensions;
*(result.values + column + row * this->dimensions) = *(this->values + ptr_offset);
};
return result;
};
Vector::Vector(const Vector &item) : Vector(item.dimensions, item.values)
{};
Vector::Vector(const unsigned short dimensions, const double values[])
{
this->dimensions = dimensions;
this->values = new double();
for (unsigned short index = 0; index < dimensions; index++)
{
this->values = values;
};
};
Vector::Vector(Vector &&item)
{
this->dimensions = item.dimensions;
this->values = item.values;
item.values = nullptr;
};
Vector::~Vector()
{
if (this->values != nullptr)
{
delete[] this->values;
};
};
Vector Vector::operator+(const Vector &other) const
{
if (this->dimensions != other.dimensions)
{
throw errors::VectorDimensionError();
};
Vector result(*this);
for (unsigned short index = 0; index < this->dimensions; index++)
{
result.values += other.values;
};
return result;
};
Vector Vector::operator+(const double other) const
{
Vector result(*this);
for (unsigned short index = 0; index < this->dimensions; index++)
{
result.values += other;
};
return result;
};
Vector Vector::operator-() const
{
Vector result = *this;
for (unsigned short index = 0; index < this->dimensions; index++)
{
result.values = -result.values;
};
return result;
};
Vector Vector::operator-(const Vector &other) const
{
Vector reversed = -other;
return *this + reversed;
};
Vector Vector::operator-(const double other) const
{
return *this + -other;
};
Vector Vector::operator*(const Vector &other) const
{
if (this->dimensions != 3 || other.dimensions != 3)
{
throw errors::VectorDimensionError();
};
Vector result(*this);
for (unsigned short index = 0; index < this->dimensions; index++)
{
result.values = this->values[(index + 1) % 3] * other.values[(index + 2) % 3] - this->values[(index + 2) % 3] * other.values[(index + 1) % 3];
};
return result;
};
Vector Vector::operator*(const double other) const
{
Vector result(*this);
for (unsigned short index = 0; index < this->dimensions; index++)
{
result.values *= other;
};
return result;
};
Vector Vector::operator/(const double other) const
{
return *this * (1.0 / other);
};
double Vector::dot(const Vector &other) const
{
if (this->dimensions != other.dimensions)
{
throw errors::VectorDimensionError();
};
double result = 0;
for (unsigned short index = 0; index < this->dimensions; index++)
{
result += this->values * other.values;
};
return result;
};
double Vector::length() const
{
double result_squared = 0;
for (unsigned short index = 0; index < this->dimensions; index++)
{
result_squared += this->values * this->values;
};
return sqrt(result_squared);
};
Vector Vector::length(const int scale) const
{
return *this / (this->length() * scale);
};
double Vector::angle(const Vector &other) const
{
return acos(this->dot(other) / (this->length() * other.length()));
};
// threads.cpp
#include <unistd.h>
#include <iostream>
#include "threads.h"
BasicThread::BasicThread(const char* name)
{
this->name.assign(name);
this->state = choices::state_free;
this->thread = new std::thread(&BasicThread::run, this);
};
choices::state BasicThread::get_state()
{
return this->state;
};
[]
std::unique_lock<std::mutex> * BasicThread::pause()
{
this->state = choices::state_paused;
std::unique_lock<std::mutex> *lock = new std::unique_lock<std::mutex>(this->mutex);
return lock;
};
void BasicThread::resume(std::unique_lock<std::mutex> &lock)
{
lock.unlock();
this->alarm.notify_all();
};
void BasicThread::run()
{
this->lock = new std::unique_lock<std::mutex>(this->mutex);
this->lock->unlock();
std::function<void ()> function;
while (this->running)
{
this->state = choices::state_running;
if (this->queue.empty())
{
this->sleep();
}
else
{
function = queue.front();
if (function)
function();
this->queue.pop();
};
};
delete this->lock;
};
void BasicThread::sleep()
{
this->state = choices::state_free;
this->alarm.wait(*this->lock);
};
void BasicThread::stop()
{
this->running = false;
this->alarm.notify_all();
this->thread->join();
this->state = choices::state_stopped;
};
void BasicThread::work(std::function<void ()> function)
{
this->queue.push(function);
this->alarm.notify_all();
};
BasicThread * DistributeThread::create(const char* name)
{
std::string name_string = name;
if (this->threads.find(name_string) != this->threads.end())
{
throw errors::ThreadExistError();
};
BasicThread *new_thread = new BasicThread(name);
this->threads = new_thread;
this->locks = std::unique_lock<std::mutex>(new_thread->mutex);
this->locks.unlock();
return new_thread;
};
bool DistributeThread::start()
{
if (this->plans.empty())
{
return false;
};
this->thread = new std::thread(DistributeThread::run, this);
return true;
};
BasicThread * DistributeThread::get(const char *thread_name)
{
std::string thread_string = thread_name;
if (this->threads.find(thread_string) == this->threads.end())
{
return this->create(thread_name);
}
else
{
return this->threads;
};
};
void DistributeThread::join()
{
this->thread->join();
};
void DistributeThread::repeat_work(const char* thread_name, unsigned int delay, std::function<void ()> function)
{
plan new_plan;
new_plan.delay = delay;
new_plan.function = function;
new_plan.thread = this->get(thread_name);
this->plans = new_plan;
this->queue.push(queue_item(delay, last_id));
last_id++;
};
void DistributeThread::run()
{
queue_item function;
plan function_plan;
while (this->running)
{
function = this->queue.top();
if (function.first > this->game_time)
{
sleep((function.first - this->game_time) / 1000);// Change milliseconds into seconds
this->game_time = function.first;
continue;
};
this->queue.pop();
function_plan = this->plans;
function_plan.thread->work(function_plan.function);
this->queue.push(queue_item(function.first + function_plan.delay, function.second));
};
};
void DistributeThread::stop()
{
this->running = false;
for (auto iterator : this->threads)
{
iterator.second->stop();
};
this->thread->join();
};
void DistributeThread::work(const char* thread_name, std::function<void ()> function)
{
this->get(thread_name)->work(function);
};
// math.h
#pragma once
double radian(const double);
class Vector
{
public:
unsigned short dimensions = 0;
double *values = nullptr;
Vector(const Vector &);
Vector(Vector &&);
Vector(const unsigned short, const double []);
~Vector();
Vector operator+(const Vector &) const;
Vector operator+(const double) const;
Vector operator-() const;
Vector operator-(const Vector &) const;
Vector operator-(const double) const;
Vector operator*(const Vector &) const;
Vector operator*(const double) const;
Vector operator/(const double) const;
double dot(const Vector &) const;
double length() const;
Vector length(const int) const;
double angle(const Vector &) const;
};
class Matrix
{
public:
unsigned short dimensions = {0, 0};
double *values = nullptr; // "*" creates a ptr pointing at an array with two dimensions.
Matrix(const Matrix &);
Matrix(Matrix &&);
Matrix(const unsigned short );
Matrix(const unsigned short , const double *); // "*" is actually a ptr pointing at the first element of an array with two dimensions.
~Matrix();
Matrix operator+(const Matrix &) const;
Matrix operator+(const double) const;
Matrix operator-() const;
Matrix operator-(const Matrix &) const;
Matrix operator-(const double) const;
Matrix operator*(const Matrix &) const;
Vector operator*(const Vector &) const;
Matrix operator*(const double) const;
Matrix operator/(const double) const;
Matrix transpose() const;
};
// threads.h
#include <condition_variable>
#include <functional>
#include <thread>
#include <map>
#include <mutex>
#include <queue>
#include <unordered_map>
#include "constants.hpp"
class BasicThread
{
friend class DistributeThread;
public:
std::string name = "Basic";
BasicThread(const char*);
choices::state get_state();
std::unique_lock<std::mutex> * pause();
void resume(std::unique_lock<std::mutex> &);
void stop();
protected:
std::condition_variable alarm;
std::unique_lock<std::mutex> *lock;
std::mutex mutex;
std::queue<std::function<void ()>> queue;
bool running = true;
choices::state state = choices::state_free;
std::thread *thread = nullptr;
void run();
void sleep();
public:
void work(std::function<void ()> function);
};
class DistributeThread
{
typedef std::pair<unsigned long long, unsigned int> queue_item;
struct plan
{
unsigned int delay;
std::function<void ()> function = nullptr;
BasicThread* thread;
};
public:
unsigned long long game_time = 0;
std::string name = "Distributor";
BasicThread * create(const char*);
BasicThread * get(const char*);
void join();
void repeat_work(const char* thread_name, unsigned int delay, std::function<void ()> function);
bool start();
void stop();
void work(const char* thread_name, std::function<void ()> function);
protected:
unsigned int last_id = 0;
std::unordered_map<std::string, std::unique_lock<std::mutex>> locks;
std::map<unsigned int, plan> plans;
std::priority_queue<queue_item, std::vector<queue_item>, std::greater<queue_item>> queue;
bool running = true;
std::unordered_map<std::string, BasicThread*> threads;
std::thread *thread = nullptr;
void run();
};
页:
[1]