如何避免指向同一地址的一组值(在.so回调调用中收集)?

时间:2010-11-22 22:24:13

标签: c++ pointers

// 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-&gt;数据的访问是在创建它的相同代码中进行的(mainloop / callback function)t;没关系。

但是无法获得队列中第一个元素的正确值!数据字段始终相同 - 通过队列访问收集的数据,只能获得上次回调中设置的值;地狱的邪恶指针!

  

str#1:bbbbaaaacccc。   str#2:bbbbaaaacccc。

回调函数定义为:

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

它返回数据的长度,** - 返回指针的指针?所以这是地址问题。

问题是,会那样  someExternalAPICallTOprocessData()fill&amp; processeddata,带有指向固定地址的指针,只存储最后一次调用的数据? 如何获取char *的副本并将其安全地放入MyStruct中?注意,下一个函数使用偏移...

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

不知何故,memcpy'ng processedData的内容似乎会破坏包含someExternalAPICallTOprocessData()的.so库。在模型上下文中,它是adder()的结尾;在真实的上下文中,它是内核网络内容的回调函数的结束;好笑。

2 个答案:

答案 0 :(得分:1)

  

那样做   someExternalAPICallTOprocessData()   将使用固定的填充和处理数据   每次通话的数据地址

这有点难以解析,但它是否“可以将someexternalApi(&amp; data)设置数据在每次调用时设置为相同的地址”,然后是的,它可以。我不知道“someExternalApi ...”是什么,但是,你必须查阅它的文档。

您可以在返回的strdup上使用processedData或将MyStruct::data更改为std::string(这将承担正确删除字符串的负担)来处理此问题你)。

答案 1 :(得分:0)

看起来你的推/弹堆栈不是线程安全的。想象一下,当你将结构推入队列时,它首先复制foo(并增加堆栈上的项目数),这会导致while循环从堆栈中弹出数据,然后然后数据被复制。糟糕。

在这种情况下,答案是确保对堆栈的所有读写操作都是原子的 - 在所有调用它的周围粘贴一个互斥锁或关键部分。