#c #multithreading #ncurses
#c #многопоточность #ncurses
Вопрос:
В настоящее время я изучаю потоки на c в университете, и у меня есть этот небольшой проект, включающий ncurses — прыгающие шары. Я хочу, чтобы шарики появлялись до тех пор, пока я не нажму «x». После того, как я нажимаю кнопку, он завершает работу, но он также показывает что-то о нарушении защиты памяти.
Когда я использую gdb, после нажатия «x» появляется надпись:
Поток 1 «p» принял сигнал SIGSEGV, ошибка сегментации. 0x00007ffff6e6b3c1 в _int_malloc (av=av@entry=0x7ffff71c2c40 , bytes=байты@entry=28) в malloc.c: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 amp;amp; 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");
}
Комментарии:
1. Большой сюрприз: можно отлаживать потоки и видеть их стек вызовов в большинстве разумных C IDE. Это возможно даже с помощью инструментов отладки более низкого уровня, таких как GDB.
2. Как выглядит
Window
класс? ВызовaddBall
в одном потоке при одновременном доступеballs[nr]
к другим может привести к сбоям.3. Не ваша ошибка, но
void updateWindow2()
это нетрадиционное место дляdelete window;
нее вызовет меньше удивления, если вы переместите ее в конецmain
, чтобы она лучше сочеталась сwindow = new Window();
.4. Добавить к комментарию @user4581301. Вероятно, использовать
new
иdelete
вручную в вашем коде — плохая идея. Вам следует взглянуть на средства динамического управления памятью стандартов c . Они гарантированно будут потокобезопасными .5. Как и просил @1201ProgramAlarm, я добавил код класса Window.
Ответ №1:
Проблема в том, что у вас есть один поток, добавляющий к balls
вектору, в то время как другие потоки читают из него.
При addBall
вызовах push_back
, если емкость вектора недостаточно велика, будет выделена новая память, существующие объекты перемещены или скопированы в новый блок, а старая память освобождена. Когда это происходит, запущенные потоки ballFunction
могут выполнять запись в память, которая больше не выделена. Это приводит к неопределенному поведению, включая ошибку сегментации, с которой вы сталкиваетесь.
Вам нужно использовать некоторую форму мьютекса или убедиться, что balls
вектору выделено достаточно места (с помощью balls.reserve(more_elements_than_youll_ever_create)
).
Кстати, ваш основной while
цикл никогда не завершится, потому что у вас есть присваивание, а не сравнение в качестве условия (используйте while (run)
или while (run == true)
).
Комментарии:
1. Большое спасибо! Это объясняет некоторые вещи — я действительно ценю это. Последний вопрос: предлагаете ли вы использовать balls.reserve в какой-либо конкретной части программы?