Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: dispatch_refresh inside a threaded_process_callback? (Read 1536 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

dispatch_refresh inside a threaded_process_callback?

My component queries last.fm to retrieve scrobbles of songs. Users can select a batch of songs, right-click and last.fm will be queried, and the scrobbles will be saved to an index-data DB. This process takes time so I'm trying to move it from something that blocks foobar into a threaded_process_callback.

This appears to be working just fine, except when I try to call dispatch_refresh inside the callback, when it crashes with:
Unhandled exception at 0x74F508F2 (KernelBase.dll) in foobar2000.exe: 0xAA67913C.

My Relevant Code:
Code: [Select]
class get_lastfm_scrobbles : public threaded_process_callback {
public:
get_lastfm_scrobbles(metadb_handle_list_cref items) : m_items(items) {}
void on_init(HWND p_wnd) {}
void run(threaded_process_status & p_status, abort_callback & p_abort) {
try {
for (size_t t = 0; t < m_items.get_count(); t++) {
p_status.set_progress(t, m_items.get_size());
p_status.set_item_path(m_items[t]->get_path());

metadb_index_hash hash;
g_client->hashHandle(m_items[t], hash);

record_t record = getRecord(hash);
getLastFmPlaytimes(hash, record);  // queries last.fm
setRecord(hash, record);

g_api->dispatch_refresh(guid_foo_enhanced_playcount_index, hash); // crashes here on first item
}
} catch (std::exception const & e) {
m_failMsg = e.what();
}
}
void on_done(HWND p_wnd, bool p_was_aborted) {
if (!p_was_aborted) {
if (!m_failMsg.is_empty()) {
popup_message::g_complain("Could not retrieve last.fm scrobbles", m_failMsg);
} else {
// finished succesfully
}
}
}
private:
pfc::string8 m_failMsg;
const metadb_handle_list m_items;
};

Am I missing something? I can't see where dispatch_refresh isn't allowed inside a thread. Do I need to batch these up and call them after a successful run or what?

Re: dispatch_refresh inside a threaded_process_callback?

Reply #1
Look at the first line of metadb.h:
Quote
//! API for tag read/write operations. Legal to call from main thread only, except for hint_multi_async() / hint_async() / hint_reader().
You need to implement main_thread_callback and dispatch the refresh from there.

Re: dispatch_refresh inside a threaded_process_callback?

Reply #2
Look at the first line of metadb.h:
Quote
//! API for tag read/write operations. Legal to call from main thread only, except for hint_multi_async() / hint_async() / hint_reader().
You need to implement main_thread_callback and dispatch the refresh from there.
Crap, I do remember reading that months ago when I was initially doing this stuff.  So I implemented main_thread_callback for doing the dispatch_refresh and that works fine now.

However, my getRecord and setRecord functions call get_user_data_here() and set_user_data() respectively, neither of which is apparently thread safe (although they aren't causing crashes currently). Since I need to loop over all the handles in the list, and call get_user_data_here and set_user_data on each, how should I handle that if it has to be done inside a main_thread_callback? Do I need to retrieve all records before even calling my threaded_process_callback, and then write everything afterwards? I don't want to move the entire logic into a main_thread_callback because that kind of defeats the purpose as it'd be back to blocking foobar for up to 1 sec per track.

Re: dispatch_refresh inside a threaded_process_callback?

Reply #3
Okay, this turned out to not be that difficult to solve.

Before I call the threaded_process_callback, I retrieve all the hashes and records for every entry in the metadb_handle_list then in the thread I call last.fm to get the scrobbles, and in my main_thread_callback I write the updated record back and then dispatch a refresh.