Как избежать того, чтобы набор значений (собранных в вызовах обратного вызова .so) указывал на один и тот же адрес? - PullRequest
0 голосов
/ 23 ноября 2010
// compile with: g++ 1.cc -o test  -Wall `pkg-config --cflags --libs glib-2.0` -lgthread-2.0
// or g++ 1.cc -o testq -lglib-2.0 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include/ -lgthread-2.0c


#include <glib.h>
#include <iostream>
#include <string.h>
int counter;
GAsyncQueue *q;

typedef struct MyStruct {
int foo;
char *data;
} *MyStructPtr;

gpointer looper(gpointer data) {
        g_thread_init(NULL);
        while (1) {
                while (g_async_queue_length(q) > 0) {
                        MyStructPtr xtransport;
                        xtransport = new struct MyStruct;
                        xtransport = (MyStructPtr)g_async_queue_try_pop(q);

 // The actual code is acting as weird, as if we have here, xtransport->data = last_text_value_ever_received;
                        std::cout << "str # " << xtransport->foo << ":" << xtransport->data << ":str\n";
                }
        }
}
void adder(char *data) {
        char *processedData;
        // someExternalAPICallToprocessData(data, &processeddata);
        processedData = (char *)data;
        MyStructPtr dtransport;
        dtransport = new struct MyStruct;

        dtransport->data = processedData;//processeddata;
        dtransport->foo = ++counter;

        g_async_queue_push(q, (gpointer*) dtransport);
}
int main() {
        GThread *l;
        g_thread_init(NULL);
        q = g_async_queue_new();
        l = g_thread_create(looper, NULL, FALSE, NULL);
        sleep(2);
        char *t;
        t = strdupa("1111");
        adder(t);
        t = strdupa("222");
        adder(t);
        sleep (5);
}

Это рабочий лабораторный макет какого-то более крупного проекта.В проекте замечено странное поведение:

вместо main (), мы сидим в функции обратного вызова, которая получает некоторые данные из системного компонента.Пытаясь напечатать (например, cout) эти данные перед помещением в очереди, можно получить что-то вроде:

N1 (при обратном вызове): aaaabbbbcccc N2 (при обратном вызове): bbbbaaaacccc.

То же самое, если доступ к (вновь установленному указателю) dtransport-> data осуществляется в том же коде, в котором они были созданы (функция mainloop / callback) t;это нормально.

Но не могу получить правильное значение первых элементов в очереди!Поля данных всегда одинаковы - доступ к собранным данным через очередь, может получить только значение, которое было установлено в последнем обратном вызове;злой указатель, черт возьми, предполагается!

str # 1: bbbbaaaacccc.str # 2: bbbbaaaacccc.

Функция обратного вызова определяется как:

int someExternalAPICallToprocessData(...., unsigned char ** data); 

Возвращает длину данных, а ** - возвращает указатель на указатель?Так что это проблема решения.

Вопрос в том, будет ли someExternalAPICallTOprocessData () заполнять и обрабатывать данные указателем на фиксированный адрес, хранящий только данные последнего вызова ?Как получить возвращаемую копию char * и безопасно поместить ее в MyStruct? Обратите внимание, что в следующей функции используются смещения ...

process(dequeued->data);
void process(char *data) {
 my *ptr = NULL;
 ptr = data + SOME_SIZE_CONST
...
}

И каким-то образом memcpy'ng содержимое processingData кажется segfault.so библиотека, которая содержит someExternalAPICallTOprocessData ().В контексте макета это конец adder ();в реальном контексте это конец функции обратного вызова для работы с сетью ядра;так смешно.

Ответы [ 2 ]

1 голос
/ 23 ноября 2010

делает это someExternalAPICallTOprocessData () будет заполнять и обрабатывать данные с фиксированным адрес данных за каждый звонок

Это немного сложно разобрать, но если бы это могло "someexternalApi (& data) установить данные для одного и того же адреса при каждом вызове", то да, это возможно. Я понятия не имею, что такое "someExternalApi ...", однако вы должны обратиться к его документации.

Вы можете справиться с этим, используя strdup для возвращенного processedData или изменив MyStruct::data на std::string (что возьмет на себя бремя правильного удаления строки из вас).

0 голосов
/ 23 ноября 2010

похоже, что ваш стек push / pop не является потокобезопасным. Представьте, что когда вы помещаете структуру в очередь, она сначала копирует foo (и увеличивает количество элементов в стеке), что приводит к тому, что цикл while извлекает данные из стека, а , а затем данные копируются. упс.

Ответ в этом случае состоит в том, чтобы убедиться, что все операции чтения и записи в стек являются атомарными - прикрепите мьютекс или критическую секцию вокруг всех обращений к нему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...