Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Physfs and multiple threads

This thread is locked; no one can reply to it. rss feed Print
Physfs and multiple threads
Addison Elliott
Member #12,394
November 2010

I've been working on a client now for some time and I just recently switched from one loop to multiple threads since I saw that it'd be more effecient. Anyways, a problem that I found was that if you have certain directories/zips in the physfs search path, then it doesn't transfer to each thread. So my question that I'm getting at is how would I be able to set a search path in physfs and have it work in each thread?

Tobias Dammers
Member #2,604
August 2002
avatar

Show some code.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Addison Elliott
Member #12,394
November 2010

I'm using a wrapper for allegro5 so I'm going to translate it back into allegro5 so you can understand it.

#SelectExpand
1void *thread_proc_call(ALLEGRO_THREAD *al_thread, void *raw_thread) 2{ 3 Client *thread = static_cast<Client *>(raw_thread); 4 thread->Main(); 5 6 return 0; 7} 8 9int main() 10{ 11 PHYSFS_init(NULL); 12 PHYSFS_addToSearchPath(".\\data\\", 1); 13 PHYSFS_addToSearchPath(".\\data\gui.zip\", 1); 14 PHYSFS_addToSearchPath(".\\data\\fonts.zip", 1); 15 16 al_set_physfs_file_interface(); 17 18 Client *client = new Client(); 19 ALLEGRO_THREAD *clientThread = al_create_thread(thread_proc_call, client); 20 al_start_thread(clientThread); 21 al_join_thread(clientThread, 0); 22} 23 24void Client::Main() 25{ 26 // Run the loop here and crap 27 al_load_bitmap("gui/background.png"); // This would fail since the file background.png is located inside gui.zip. 28 // Note: I have tried to initialize physfs again in this function so it would work in the thread and it didn't seem to work. 29}

Just to make sure, this code looks a lot better with the wrapper. This is just an example of what i'm trying to do :P

Peter Wang
Member #23
April 2000

You need to call al_set_physfs_file_interface in the thread.

Addison Elliott
Member #12,394
November 2010

Still doesn't seem to work.

Edit: Alright, I did some basic testing to get some more information on the problem. When I put the al_set_physfs_file_interface function inside Client::Main and then put al_load_bitmap("gui/background.png") it loads fine. But I guess there may be something wrong with where I currently have it.
I have two current threads: Renderer & Client right now. I load the bitmap from Renderer::LoadState. The way I communicate between Renderer & Client is through custom states. It'd be best to show you some code so you can understand what I'm doing.

#SelectExpand
1Renderer::Renderer(a5::Config &config_, Client &client_) : config(config_), client(client_), display(640, 480, a5::Display::Windowed), gui(*this), fpsTimer(1.0), fps(0), redraw(true) 2{ 3 //PHYSFS_init(NULL); 4 //PHYSFS_addToSearchPath(".\\data\\", 1); 5 //PHYSFS_addToSearchPath(".\\data\\gui.zip", 1); 6 //PHYSFS_addToSearchPath(".\\data\\fonts.zip", 1); 7 8 //al_set_physfs_file_interface(); 9 10 display.SetTitle("Chronos Online"); 11 display.Target(); 12 13 queue.Register(display); 14 queue.Register(keyboard); 15 queue.Register(mouse); 16 queue.Register(fpsTimer); 17 queue.Register(client); 18 client.Queue().Register(*this); 19 20 bitmapLoader.reset(new BitmapLoader(atoi(config.GetValue("", "ImageCacheLimit").c_str()))); 21 fontLoader.reset(new FontLoader()); 22 Emit(new RendererController::GetStateEvent()); 23} 24 25void Renderer::Main() 26{ 27 al_set_physfs_file_interface(); 28 fpsTimer.Start(); 29 30 while (true) 31 { 32 a5::Event_Reader event(queue); 33 34 event.WaitNext(); 35 36 Client::Event *clientEvent; 37 38 switch (event.Type()) 39 { 40 case a5::Display::Event::Type: DisplayEvent(event.Display()); break; 41 case a5::Keyboard::Event::Type: KeyboardEvent(event.Keyboard()); break; 42 case a5::Mouse::Event::Type: MouseEvent(event.Mouse()); break; 43 case a5::Timer::Event::Type: TimerEvent(event.Timer()); break; 44 45 default: 46 if ((clientEvent = dynamic_cast<Client::Event *>(&event.Event()))) 47 ClientEvent(*clientEvent); 48 } 49 50 if (redraw) 51 { 52 Render(); 53 redraw = false; 54 } 55 } 56} 57 58void Renderer::ClientEvent(const Client::Event &ce) 59{ 60 if (ce.subtype == Client::Event::UpdateState) 61 { 62 LoadState(static_cast<const Client::UpdateStateEvent *>(&ce)->state); 63 } 64} 65 66void Client::Main() 67{ 68 al_set_physfs_file_interface(); 69 a5::Bitmap *bitmap = new a5::Bitmap("gui/background.png"); 70 printf("no error\n"); 71 gameTimer.Start(); 72 73 while (true) 74 { 75 a5::Event_Reader event(queue); 76 77 event.WaitNext(); 78 79 RendererController::Event *rendererEvent; 80 //Net::Event *event; 81 82 switch (event.Type()) 83 { 84 case a5::Timer::Event::Type: TimerEvent(event.Timer()); break; 85 default: 86 if ((rendererEvent = dynamic_cast<RendererController::Event *>(&event.Event()))) 87 RendererEvent(*rendererEvent); 88 } 89 } 90} 91 92void Client::RendererEvent(const RendererController::Event &re) 93{ 94 if (re.subtype == RendererController::Event::GetState) 95 { 96 Emit(new Client::UpdateStateEvent(GetState())); 97 } 98}

It might be hard to understand with the wrapper but basically, when Renderer is constructed it sends GetStateEvent which the client receives in the Main thread. The client sends UpdateStateEvent back to the Renderer and in the Renderer Main thread it calls LoadState(where I am currently loading the bitmap) I call al_set_physfs_file_interface inside Renderer::Main(), so I'm not sure what the problem is.

Peter Wang
Member #23
April 2000

I can't tell if you understood this point, so apologies if this sounds patronising.

al_set_physfs_file_interface only changes the file interface for the calling thread. If you call it in the Renderer thread, it only affects the Renderer thread. The call to al_load_bitmap from within the Client thread will have the default behaviour, which is to load from the native file system, not through PhysicsFS.

Hope that helps.

Go to: