2011-08-25 25 views
0

自动变量我想绕过线程的一些数据,但要使用全局变量,如果我可以管理它避免。我写了我的线程程序的方式有一个单独的函数通过为每个线程的生命周期中的“相”的用户:举例来说,这将是产生线程的典型用法:访问和修改另一个线程的堆栈

void init_thread(void *arg) { 
    graphics_init(); 
} 
void process_msg_thread(message *msg, void *arg) { 
    if (msg->ID == MESSAGE_DRAW) { 
    graphics_draw(); 
    } 
} 
void cleanup_thread(void *arg) { 
    graphics_cleanup(); 
} 

int main() { 
    threadCreator factory; 
    factory.createThread(init_thread, 0, process_msg_thread, 0, cleanup_thread, 0); 
    // even indexed arguments are the args to be passed into their respective functions 
    // this is why each of those functions must have a fixed function signature is so they can be passed in this way to the factory 
} 

// Behind the scenes: in the newly spawned thread, the first argument given to 
// createThread() is called, then a message pumping loop which will call the third 
// argument is entered. Upon receiving a special exit message via another function 
// of threadCreator, the fifth argument is called. 

的最直接方式要做到这一点是使用全局。我想尽量避免这样做,因为它是不好的编程习惯,因为它会产生混乱。

一定出现问题时,我尝试稍微改进我的例子:

void init_thread(void *arg) { 
    GLuint tex_handle[50]; // suppose I've got 50 textures to deal with. 
    graphics_init(&tex_handle); // fill up the array with them during graphics init which loads my textures 
} 
void process_msg_thread(message *msg, void *arg) { 
    if (msg->ID == MESSAGE_DRAW) { // this message indicates which texture my thread was told to draw 
    graphics_draw_this_texture(tex_handle[msg->texturehandleindex]); // send back the handle so it knows what to draw 
    } 
} 
void cleanup_thread(void *arg) { 
    graphics_cleanup(); 
} 

我大大简化这里的图形系统的交互,但你明白了吧。在该示例中代码tex_handle是一个自动可变的,并且init_thread完成时其所有值都被丢失,所以将不提供当process_msg_thread需要引用它。

我可以使用全局解决这个问题,但是这意味着我不能(例如)其中两个线程同时有,因为他们将彼此的质感把手名单上践踏,因为它们使用相同的一个。

我可以使用线程局部全局,但是是一个好主意?

,我想出了最后一个念头。我可以在我的父线程的堆中分配存储空间,并发送一个指向子节点的指针。所以我可以在父线程离开时释放它,因为我打算在它退出之前清理它的子线程。所以,这样的事情:

void init_thread(void *arg) { 
    GLuint *tex_handle = (GLuint*)arg; // my storage space passed as arg 
    graphics_init(tex_handle); 
} 
void process_msg_thread(message *msg, void *arg) { 
    GLuint *tex_handle = (GLuint*)arg; // same thing here 
    if (msg->ID == MESSAGE_DRAW) { 
    graphics_draw_this_texture(tex_handle[msg->texturehandleindex]); 
    } 
} 
int main() { 
    threadCreator factory; 
    GLuint *tex_handle = new GLuint[50]; 
    factory.createThread(init_thread, tex_handle, process_msg_thread, tex_handle, cleanup_thread, 0); 
    // do stuff, wait etc 
    ... 
    delete[] tex_handle; 
} 

这看上去或多或少安全的,因为我的价值观去堆,我的主线程分配,然后它可以让孩子惹它按照自己的意愿。由于指针被赋予所有需要访问的功能,因此孩子们可以自由使用存储空间。

所以这让我想到,为什么不只是它是一个自动变量:

int main() { 
    threadCreator factory; 
    GLuint tex_handle[50]; 
    factory.createThread(init_thread, &tex_handle, process_msg_thread, &tex_handle, cleanup_thread, 0); 
    // do stuff, wait etc 
    ... 
} // tex_handle automatically cleaned up at this point 

这意味着孩子线程直接访问父的堆栈。我想知道这是否是犹太教。 我在网上找到了这个:http://software.intel.com/sites/products/documentation/hpc/inspectorxe/en-us/win/ug_docs/olh/common/Problem_Type__Potential_Privacy_Infringement.htm

看来英特尔Inspector XE检测到这种行为。所以也许我不应该这样做?这是否仅仅是URL的建议中对隐私侵权的警告,还是可能出现的其他潜在问题,我不知道?

P.S.在思考完所有这些之后,我意识到也许这种将线程分解为一堆独立调用的函数的架构并不是一个好主意。我的意图是消除为产生的每个线程编写消息处理循环的复杂性。我曾预料到可能存在的问题,如果我有一个总是检查消息的线程实现(比如我的自定义线程将被终止),那么我可以保证一些未来的用户不会意外忘记检查这个条件在他们的每个消息循环中。

我的解决方案的问题是,这些单独的功能现在是分开的,不能相互通信。他们可能只能通过全局变量和线程本地全局变量来实现。我猜想线程本地全局变量可能是我最好的选择。

P.P.S.这让我想起了RAII以及线程的概念,至少如我最终表示的那样,它与资源有一定的相似性。也许我可以建立一个比传统方式更自然地表现线程的对象......不知何故。我想我会去睡觉。

回答

2

将你的线程函数放到一个类中。然后他们可以使用实例变量进行通信这要求您的线程工厂进行更改,但是解决您的问题的最简单方法。

只要您可以保证堆栈框架包含数据的函数在您的子线程退出之前永远不会返回,您的使用自动变量的想法也将起作用。这并不容易实现,即使main()返回子线程仍然可以运行。