В конце концов я обнаружил, что причиной segfault было мое присоединение к пулу потоков из основного потока после вызова thread_pool.apply_async. Я удалил операторы close и join, и прямое соединение по сигналу работало нормально, как и ожидалось. Я продолжал получать предупреждение:
QObject::setParent: Cannot set parent, new parent is in a different thread
Но программа работала, как и ожидалось. Спасибо!
Часть беспорядка - то, что это по сути более трудно в C. malloc
и free
подобны new
и delete
: malloc
выделяет новую память и возвращает указатель на ту память. free
делает ту память доступной снова, пока это - память, которая была выделена с помощью malloc. Иначе это просто делает хеш некоторого блока памяти. Это не заботится.
Важная вещь с malloc/free состоит в том, чтобы выбрать и последовательно поддерживать дисциплинированное использование. Вот некоторые подсказки:
ВСЕГДА проверяйте возвращенный указатель от malloc для ПУСТОГО УКАЗАТЕЛЯ
if((p = (char *) malloc(BUFSIZ)) == NULL {
/* then malloc failed do some error processing. */
}
Для пояса и безопасности подтяжек, установленной в NULL указатель после освобождения его.
free(p);
p = NULL ;
попробуйте к malloc и освободите блок памяти в том же объеме если возможный:
{ char * p ;
if((p = malloc(BUFSIZ)) == NULL {
/* then malloc failed do some error processing. */
}
/* do your work. */
/* now you're done, free the memory */
free(p);
p = NULL ; /* belt-and suspenders */
}
Когда Вы не можете, прояснить, что то, что Вы возвращаете, malloc
'память редактора, таким образом, вызывающая сторона может освободить его.
/* foo: do something good, returning ptr to malloc memory */
char * foo(int bar) {
return (char *) malloc(bar);
}
При записи этого я понял, что это - больше вопрос обо мне понимающий поток C, чем что-либо еще, но один вопрос за один раз.
Я честно думаю, что необходимо читать на K&R, если Вы не имеете.
К сожалению, существуют ограниченные стратегии автоматизации выделения памяти и освобождения в C. Компилятор C++ генерирует много кода негласно для Вас - он отслеживает каждую переменную на стеке и удостоверяется, что соответствующий деструктор называют, когда стек очищен. Это - на самом деле довольно сложный тип генерации кода, особенно когда Вы выдаете исключения в соединение.
C, с другой стороны, намного более просто, который является, почему это иногда называют "ассемблером высокого уровня". C не имеет никакого механизма, чтобы гарантировать, что конкретный бит кода называют, когда функция выходит, или переменная выталкивается от стека, так Вам решать для отслеживания каждый бит памяти, которую Вы выделяете, и каждый файл или сеть снабжают Вас сокетом, открываются и очищают их в соответствующей точке. Нет никакого практического способа создать автоматический интеллектуальный указатель в C.
Одно понятие, на которое необходимо посмотреть, является "пулами памяти". В основном, скорее та попытка отслеживать каждый отдельный блок памяти, которую Вы выделяете, Вы создаете пул, сделайте некоторый блок работы, поместив каждый блок памяти, который Вы выделяете в пул, затем освобождаете целый пул, когда Вы сделаны. Вы обмениваете определенную производительность и управляете здесь для упрощения познавательной нагрузки на программиста, но большую часть времени это определенно стоит того.
Необходимо посмотреть на Apache Портативный проект Во время выполнения. У них есть библиотека пула памяти (документы по http://apr.apache.org/docs/apr/1.3/group__apr__pools.html). Если APR слишком много, чтобы Вы погрузились в, можно реализовать очень простой пул памяти с помощью трех функций и структуры данных связанного списка. Псевдокод был бы чем-то как:
struct Pool {
void* memoryBlock;
struct Pool *next;
}
struct Pool *createPool(void) {
/* allocate a Pool and return it */
}
void addToPool(struct Pool *pool, void *memoryBlock) {
/* create a new Pool node and push it onto the list */
}
void destroyPool(struct Pool *pool) {
/* walk the list, free each memory block then free its node */
}
Используя пул что-то вроде этого:
int main(void) {
struct Pool *pool = createPool();
/* pool is empty */
doSomething(pool);
/* pool full of crap, clean it up and make a new one */
destroyPool(pool);
pool = createPool();
/* new pool is empty */
doMoreStuff(pool);
destroyPool(pool);
return 0;
}
Печальная истина - то, что C действительно не разработан для инкапсуляции всех тех проблем управления памятью.
При рассмотрении довольно высококачественных API как POSIX Вы будете видеть, что общий шаблон - то, что Вы передаете указатель на указатель на функцию, которая затем выделяет память, и что Вы позже передаете его снова функции, которая уничтожает его.
Это не обязательно изящно, но я не думаю, что существует много способов сделать это действительно изящным, не моделируя ООП в C.
Хорошо в C необходимо сделать все Вы управление памятью вручную, поскольку Вы уже обнаружили. Это должно не быть удивительно.
Обычный путь
MyType *ptr = malloc(array_size * sizeof *ptr);
Но если Вы хотите быть совместимыми с C++, сделать
MyType *ptr = (MyType*) malloc(array_size * sizeof *ptr);
Можно также сделать макрос
#define MALLOC( NUMBER, TYPE ) ( TYPE * ) malloc( NUMBER * sizeof( TYPE ) )
MyType *ptr = MALLOC(10, MyType);
Конечно, без RAII, удостоверьтесь когда-то позже, что Вы имеете
free(ptr);
Можно думать, что то, что я говорю, странно, но нет никакой большой разницы между C++ и C. C имеет RAII также. RAII не принадлежит C++ только.
Только вещь у Вас должно быть достаточно дисциплины, чтобы сделать управление.
Класс C++:
class foo {
public:
ofstream ff;
int x,y;
foo(int _x) : x(_x),y(_x){ ff.open("log.txt"); }
void bar() { ff<<x+y<<endl; }
};
int main()
{
auto_ptr<foo> f(new foo);
f->bar();
}
C объект
typedef struct FOO {
FILE *ff;
int x,y;
} *foo_t;
foo_t foo_init(int x)
{
foo_t p=NULL;
p=malloc(sizeof(struct FOO)); // RAII
if(!p) goto error_exit;
p->x=x; p->y=x;
p->ff=fopen("log.txt","w"); // RAII
if(!p->ff) goto error_exit;
return p;
error_exit: // ON THROW
if(p) free(p);
return NULL;
}
void foo_close(foo_t p)
{
if(p) fclose(p->ff);
free(p);
}
void foo_bar(foo_t p)
{
fprintf(p->ff,"%d\n",p->x+p->y);
}
int main()
{
foo_t f=foo_init(1);
if(!f) return 1;
foo_bar(f);
foo_close(f);
return 0;
}
Один путь I "скрывает" выделение памяти, и освобождение должно выдать его к пользовательским контейнерам. Передайте контейнер объект un-malloced. Позвольте ему волноваться о malloc и когда я удалю объект, которому позволяют это волноваться о свободном. Конечно, это только работает, если Вы только храните объект в одном контейнере. Если у меня будут ссылки на объект повсеместно, то я создам эквивалент конструктора и методов деструктора с синтаксисом C:
glob* newGlob();
void freeGlob(glob* g);
(объектом я имею в виду что-либо, на что Вы указали бы на - не объекты C++).
Я не совсем уверен, что Вы спрашиваете, но C довольно прост:
struct Foo *f0 = malloc(sizeof(*f)); // alloc uninitialized Foo struct
struct Foo *f1 = calloc(1,sizeof(*f)); // alloc Foo struct cleared to all zeroes
//You usually either want to clear your structs using calloc on allocation, or memset. If
// you need a constructor, just write a function:
Foo *Foo_Create(int a, char *b)
{
Foo *r = calloc(1,sizeof(*r));
r->a = a;
r->b = strdup(b);
return r;
}
Here is a simple C workflow with arrays:
struct Foo **foos = NULL;
int n_foos = 0;
...
for(i = 0; i < n_foos; ++i)
{
struct Foo *f = calloc(1,sizeof(*f));
foos = realloc(foos,sizeof(*foos)*++n_foos); // foos before and after may be different
foos[n_foos-1] = f;
}
Если Вы становитесь необычными, можно записать макросы для помощи:
#define MALLOCP(P) calloc(1,sizeof(*P)) // calloc inits alloc'd mem to zero
Несколько точек:
Существует много, можно сделать для создания жизни легче. Вы уже, кажется, пришел в голову идею создать фабрики/конструкторов для Ваших C-объектов. Это - хорошее начало, следуют ему.
Некоторые другие идеи рассмотреть.
не соглашайтесь на стандарт malloc/free., идут, ища лучший, это было opensourced или пишет тот, что комплекты использование памяти объектов, которые Вы создаете. также, мы говорим C здесь, Вы собираетесь перезаписать свои объекты, свободные больше и однажды и забыть освобождать некоторых, поэтому встройте некоторую поддержку отладки в свою запись malloc., что Ваше собственное не твердо, если Вы не можете найти тот, который удовлетворяет Ваши потребности.
используйте больше чем одну "кучу". используйте один в классе объекта, Вы создаете, используете временную "кучу", если Вы знаете Вас, Вы собираетесь иметь большое количество временных объектов, которые связаны, это подавляет фрагментацию памяти и позволяет Вам управлять памятью согласно использованию.
взгляд на стратегии как пулы Objective C
если Вы думаете, что понимаете, как C++ работает, то добавление поведения конструктора к выделению памяти на объектной фабрике не настолько трудно сделать, и использование сделанного на заказ свободного может затем предоставить Вам возможность назвать деструктор на объекте, являющемся free'd предоставление Вас назад часть поведения C++, которое Вы любили
Я не знаю, как скрыть их и как автоматизировать вещи.
C и C++ являются различными языками. Теперь, скажите что сто раз себе. Будьте громкими.
Что Вы подразумеваете под сокрытием? Что делает Вы подразумеваете, автоматизируют? Можно ли отправить некоторые примеры? Почему необходимо скрыть и/или автоматизировать.
Хорошие места онлайн для начинаний с выделением памяти C: