// 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()的结尾;在真实的上下文中,它是内核网络内容的回调函数的结束;好笑。
答案 0 :(得分:1)
那样做 someExternalAPICallTOprocessData() 将使用固定的填充和处理数据 每次通话的数据地址
这有点难以解析,但它是否“可以将someexternalApi(&amp; data)设置数据在每次调用时设置为相同的地址”,然后是的,它可以。我不知道“someExternalApi ...”是什么,但是,你必须查阅它的文档。
您可以在返回的strdup
上使用processedData
或将MyStruct::data
更改为std::string
(这将承担正确删除字符串的负担)来处理此问题你)。
答案 1 :(得分:0)
看起来你的推/弹堆栈不是线程安全的。想象一下,当你将结构推入队列时,它首先复制foo(并增加堆栈上的项目数),这会导致while循环从堆栈中弹出数据,然后然后数据被复制。糟糕。
在这种情况下,答案是确保对堆栈的所有读写操作都是原子的 - 在所有调用它的周围粘贴一个互斥锁或关键部分。