我目前在uni学习c ++中的线程,我有一个涉及ncurses的小项目 - 弹跳球。我希望球能够产生,直到我按'x'。按下按钮后,它会退出,但它也会显示有关内存保护违规的信息。
当我使用gdb时,按'x'后,它说:
线程1“p”接收信号SIGSEGV,分段故障。 malloc.c中的_int_malloc(av = av @ entry = 0x7ffff71c2c40,bytes = bytes @ entry = 28)中的0x00007ffff6e6b3c1:3612
问题可能出在for循环中,但我不确定。
我写的代码是:
#include "window.h"
#include <stdlib.h>
#include <time.h>
#include <thread>
#include <unistd.h>
#include <ncurses.h>
#include <atomic>
Window *window;
std::atomic<bool> run(true);
void exit() {
while(run) {
char z = getch();
if(z == 'q') run = false;
}
}
void ballFunction(int a) {
int nr = a;
while (run && window->balls[nr]->counter < 5) {
usleep(50000);
window->balls[nr]->updateBall();
}
window->balls[nr]->x = -1;
window->balls[nr]->y = -1;
}
void updateWindow2() {
while(run) {
usleep(50000);
window->updateWindow();
}
delete window;
}
int main() {
srand(time(NULL));
window = new Window();
int i = 0;
std::vector<std::thread> threads;
std::thread threadWindow(updateWindow2);
std::thread threadExit(exit);
while(run = true) {
window->addBall();
threads.push_back(std::thread(ballFunction, i));
i++;
sleep(1);
}
threadWindow.join();
threadExit.join();
for(int j=2; j<i+2; j++) {
threads[j].join();
}
return 0;
}
#include "window.h"
#include <ncurses.h>
#include <unistd.h>
Window::Window()
{
initWindow();
}
Window::~Window()
{
endwin();
}
void Window::initWindow()
{
initscr();
noecho();
curs_set(FALSE);
clear();
refresh();
}
void Window::addBall()
{
Ball *ball = new Ball(this->ballCounter++);
this->balls.push_back(ball);
}
void Window::updateWindow()
{
for(int i = 0; i<ballCounter; i++)
{
if(balls[i]->update())
{
clear(balls[i]->yy,
balls[i]->xx);
drawBall(balls[i]->y,
balls[i]->x);
}
}
refresh();
}
void Window::clear(int y, int x)
{
mvprintw(y, x, " ");
}
void Window::drawBall(int y, int x)
{
mvprintw(y, x, "o");
}
问题是你有一个线程添加到balls
向量,而其他线程正在读取它。
当addBall
调用push_back
时,如果向量容量不够大,将分配新内存,将现有对象移动或复制到新块,并释放旧内存。发生这种情况时,运行ballFunction
的线程可以写入不再分配的内存。这会导致未定义的行为,包括您遇到的分段错误。
您需要使用某种形式的互斥,或确保balls
向量分配了足够的空间(使用balls.reserve(more_elements_than_youll_ever_create)
)。
在一个不相关的注释中,你的主要while
循环永远不会终止,因为你有一个赋值而不是比较作为条件(使用while (run)
或while (run == true)
)。