|
This thread is locked; no one can reply to it. |
1
2
|
help with threads |
shadyvillian
Member #12,426
December 2010
|
I'm trying to put this function on a separate thread so it can run while the user still using the program. heres the function: 1void core::saveDeck()
2{
3 double start = al_get_time();
4 string path = "Decks/"+deckName+".deck";
5 remove(path.c_str());
6 ofstream oFile(path.c_str());
7 CURL *curl;
8 FILE *file;
9
10 string flag = "n";
11 vector<card> mainboard = listItemViewer[MAIN_TAB_DECK].getCardList(), sideboard = listItemViewer[MAIN_TAB_DECK+1].getCardList();
12
13 if(sideboard.size() > 0)
14 {
15 flag = "y";
16 }
17
18 for(unsigned int i = 0; i < mainboard.size(); i++)
19 {
20 oFile << mainboard[i].set << "*" << mainboard[i].numberOf << "*" << mainboard[i].name << "*" << endl;
21 }
22
23 oFile << "sideboard " + flag << endl;
24
25 if(flag == "y")
26 {
27 for(unsigned int i = 0; i < sideboard.size(); i++)
28 {
29 oFile << sideboard[i].set << "*" << sideboard[i].numberOf << "*" << sideboard[i].name << "*" << endl;
30 }
31 }
32
33 oFile.close();
34
35 file = fopen(("Decks/"+deckName+".deck").c_str(), "rb");
36
37 curl_global_init(CURL_GLOBAL_ALL);
38
39 /* get a curl handle */
40 curl = curl_easy_init();
41
42 if(curl)
43 {
44 /* enable uploading */
45 curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
46
47 curl_easy_setopt(curl, CURLOPT_USERPWD, "username:password");
48
49 /* specify target */
50 curl_easy_setopt(curl,CURLOPT_URL, ("ftp://216.51.232.61/UserData/"+userName+"/"+deckName+".deck").c_str());
51
52 /* now specify which file to upload */
53 curl_easy_setopt(curl, CURLOPT_READDATA, file);
54
55 /* Now run off and do what you've been told! */
56 curl_easy_perform(curl);
57
58 /* always cleanup */
59 curl_easy_cleanup(curl);
60 }
61
62 fclose(file);
63 curl_global_cleanup();
64 cout << "save deck took: " << al_get_time()-start<< " seconds" << endl;
65}
It uses variables from the main thread and everything is wrapped in a class. processingThread = al_create_thread(saveDeck, NULL); al_start_thread(processingThread); Not sure what I need for the second parameter, I'm not returning any data. Can anyone help me out? Software Engineer by day, hacker by night. |
Todd Cope
Member #998
November 2000
|
The second parameter can be NULL if you don't need it. You should use mutexes (al_lock_mutex()/al_unlock_mutex) to lock data that is being accessed from the main thread. You mainly want to make sure none of the data you are writing to the file is going to be modified by the main thread while this thread is writing the file. |
weapon_S
Member #7,859
October 2006
|
shadyvillian said: It uses variables from the main thread Put those in a struct and use as argument? (Might make it harder to ensure main-thread doesn't F them up.) |
axilmar
Member #1,204
April 2001
|
shadyvillian said: Can anyone help me out? What is the actual problem? |
shadyvillian
Member #12,426
December 2010
|
It doesn't like the function I'm supplying it. Does the thread have to be a paramter in the function? What if everything is just in a class scope? EDIT: messing around with this I might almost have it 1struct SaveData
2{
3 std::vector<card> mainboard, sideboard;
4 std::string userName, deckName;
5
6 SaveData(std::vector<card> main, std::vector<card> side, std::string user, std::string deck)
7 {
8 mainboard = main;
9 sideboard = side;
10 userName = user;
11 deckName = deck;
12 }
13};
14
15 SaveData *data = arg(*SaveData);
16
17 ofstream oFile(("Decks/"+data->deckName+".deck").c_str());
18 CURL *curl;
19 FILE *file;
20
21 string flag = "n";
22
23 if(data.sideboard.size() > 0)
24 {
25 flag = "y";
26 }
27
28 for(unsigned int i = 0; i < data->mainboard.size(); i++)
29 {
30 oFile << data->mainboard[i].set << "*" << data->mainboard[i].numberOf << "*" << data->mainboard[i].name << "*" << endl;
31 }
32
33 oFile << "sideboard " + flag << endl;
34
35 if(flag == "y")
36 {
37 for(unsigned int i = 0; i < data->sideboard.size(); i++)
38 {
39 oFile << data->sideboard[i].set << "*" << data->sideboard[i].numberOf << "*" << data->sideboard[i].name << "*" << endl;
40 }
41 }
42
43 oFile.close();
44 file = fopen(("Decks/"+data->deckName+".deck").c_str(), "rb");
45 curl_global_init(CURL_GLOBAL_ALL);
46 curl = curl_easy_init();
47
48 if(curl)
49 {
50 curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
51 curl_easy_setopt(curl, CURLOPT_USERPWD, "username:password");
52 curl_easy_setopt(curl,CURLOPT_URL, ("ftp://216.51.232.61/UserData/"+data->userName+"/"+data->deckName+".deck").c_str());
53 curl_easy_setopt(curl, CURLOPT_READDATA, file);
54 curl_easy_perform(curl);
55 curl_easy_cleanup(curl);
56 }
57
58 fclose(file);
59 curl_global_cleanup();
60}
61
62SaveData data = SaveData(listItemViewer[MAIN_TAB_DECK].getCardList(), listItemViewer[MAIN_TAB_DECK+1].getCardList(), userName, deckName);
63 processingThread = al_create_thread(saveDeck(processingThread, &data), NULL); //error here
64 al_start_thread(processingThread);
I get this error. Does my function need to be static or something? error: invalid conversion from 'void*' to 'void* (*)(ALLEGRO_THREAD*, void*)' [-fpermissive]| Software Engineer by day, hacker by night. |
J-Gamer
Member #12,491
January 2011
|
It does indeed have trouble with member functions that aren't static(ie: tied to one instance of the class). If it has to be tied to a class instance, you'd need the mem_fn functions of the std library. Also, the function that you put in al_create_thread should accept a void* parameter. " There are plenty of wonderful ideas in The Bible, but God isn't one of them." - Derezo |
shadyvillian
Member #12,426
December 2010
|
I decided to make it a non-member function and just pass a struct to make it easier now. Now I'm getting a crash on oFile << data->mainboard[i].set << "*" << data->mainboard[i].numberOf << "*" << data->mainboard[i].name << "*" << endl;
#0 005ADCC5 std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) () (??:??) Is there something else I need to do? Do I need to use a mutex? Software Engineer by day, hacker by night. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Uhm, looks like you accessed an out of bounds string... That's my first guess. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
shadyvillian
Member #12,426
December 2010
|
Their fine before they go through to the thread. Is there something I have to do to be able to use them or pass them different? latest code: 1void *saveDeck(ALLEGRO_THREAD *thread, void *arg)
2{
3 SaveData *data = (SaveData*)arg;
4 CURL *curl;
5 stringstream buffer(stringstream::out);
6 string flag = "n";
7
8 al_lock_mutex(data->mutex);
9
10 if(data->sideboard.size() > 0)
11 {
12 flag = "y";
13 }
14
15 for(unsigned int i = 0; i < data->mainboard.size(); i++)
16 {
17 buffer << data->mainboard[i].set << "*" << data->mainboard[i].numberOf << "*" << data->mainboard[i].name << "*" << endl;
18 }
19
20 buffer << "sideboard " + flag << endl;
21
22 if(flag == "y")
23 {
24 for(unsigned int i = 0; i < data->sideboard.size(); i++)
25 {
26 buffer << data->sideboard[i].set << "*" << data->sideboard[i].numberOf << "*" << data->sideboard[i].name << "*" << endl;
27 }
28 }
29 curl_global_init(CURL_GLOBAL_ALL);
30 curl = curl_easy_init();
31
32 if(curl)
33 {
34 curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
35 curl_easy_setopt(curl, CURLOPT_USERPWD, "username:password");
36 curl_easy_setopt(curl,CURLOPT_URL, ("ftp://216.51.232.61/UserData/"+data->userName+"/"+data->deckName+".deck").c_str());
37 curl_easy_setopt(curl, CURLOPT_READDATA, &buffer);
38 curl_easy_perform(curl);
39 curl_easy_cleanup(curl);
40 }
41
42 curl_global_cleanup();
43 al_unlock_mutex(data->mutex);
44 return NULL;
45}
46
47SaveData data = SaveData(listItemViewer[MAIN_TAB_DECK].getCardList(), listItemViewer[MAIN_TAB_DECK+1].getCardList(), userName, deckName);
48processingThread = al_create_thread(saveDeck, &data);
49al_start_thread(processingThread);
Software Engineer by day, hacker by night. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
It appears as if you're using a vector, and you use the size function, so your bounds should be right. That also means you're using C++, which means you could make this a member function of your SaveData class, instead of a global c-style function. That's how I would do it, but it's not necessary I guess. As to your problem, your code should work as long as arg is a valid pointer to a valid SaveData object. And it should work fine from any thread as long as the mutex is locked properly, which it appears to be. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
J-Gamer
Member #12,491
January 2011
|
Edgar Reynaldo said: That also means you're using C++, which means you could make this a member function of your SaveData class, instead of a global c-style function. That's how I would do it, but it's not necessary I guess. It'd have to be static to be able to do that, though. The fun thing is that static functions can access the private parts if they have a pointer to an instance of their class. " There are plenty of wonderful ideas in The Bible, but God isn't one of them." - Derezo |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Errr... I don't see why it would have to be static.. Member functions can always access static data, it's just that static functions can't access non-static data members without a pointer or an object. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
J-Gamer
Member #12,491
January 2011
|
The problem with member functions is that they need an extra parameter(this). And I honestly can't get mem_fun to work(edit: with the second parameter being a reference. mem_fun uses references itself for its parameters, and you can't have a reference to a reference). " There are plenty of wonderful ideas in The Bible, but God isn't one of them." - Derezo |
Edgar Reynaldo
Major Reynaldo
May 2007
|
I've never had good luck with the standard library's mem_fun adaptors. If you really need something like that I would just break down and use Boost. (And FFS don't tell bambam I said that.) What do you need them for? My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
J-Gamer
Member #12,491
January 2011
|
I had a class called Transformation, which had a function apply(Point& p). I wanted to use that function on all points in a list, so I tried doing it with this line of code: " There are plenty of wonderful ideas in The Bible, but God isn't one of them." - Derezo |
Edgar Reynaldo
Major Reynaldo
May 2007
|
My first attempt to solve it would be to make Transformation::Apply take a pointer instead of a reference. That way you can still alter it, and mem_fun should be happy because it then has a reference to a pointer. ? My 2c. Like I said, I never had good luck with mem_fun. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
J-Gamer
Member #12,491
January 2011
|
That should indeed work, but the project has been written and the deadline has passed. The problem would still be that it's still a list of Points, not of Point*'s. That would need another workaround: a function accepting a Point and calling the bind1st(mem_fun()) function on the pointer. Edit: void apply_point(Transformation* t, Point& p) { t->apply(p); }; for_each(points.begin(), points.end(), bind1st(apply_point, &trans)); This is my workaround, but it uses more lines than a for-iteration over the list and manually calling apply. " There are plenty of wonderful ideas in The Bible, but God isn't one of them." - Derezo |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Do you really need to save three lines though? Seems like OCD.... My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
J-Gamer
Member #12,491
January 2011
|
I just don't like writing extra functions for small things that aren't reusable at all. Just having a for-loop over the list is much more understandable code. " There are plenty of wonderful ideas in The Bible, but God isn't one of them." - Derezo |
shadyvillian
Member #12,426
December 2010
|
Am I doing it right? I start the thread and both are just doing their thing. The second thread will only run for about 5 seconds. Is there something I need to do once the function is done executing on the second thread?(like at the end of the function or in the main thread? Join the threads?) Software Engineer by day, hacker by night. |
J-Gamer
Member #12,491
January 2011
|
You'll need to call al_destroy_thread to free up the resources. But only after you are 100% sure the thread has finished running. I think you can do that by calling al_join_thread. " There are plenty of wonderful ideas in The Bible, but God isn't one of them." - Derezo |
shadyvillian
Member #12,426
December 2010
|
Even when I don't use any data in my function it still crashes when I excute it and its not telling me why EDIT: commenting out the libcurl stuff gets rid of the error... Does anyone know if libcurl's easy inference thread safe? EDIT: Turns out curl_global_init isn't thread safe. For any libcurl users out there is there a workaround for this? Software Engineer by day, hacker by night. |
J-Gamer
Member #12,491
January 2011
|
Make it thread-safe yourself? Put a global mutex in and lock it each time you want to use libcurl. Then unlock it when you're done. If you do this consistently throughout your program, two threads will never try to access libcurl at the same time. " There are plenty of wonderful ideas in The Bible, but God isn't one of them." - Derezo |
shadyvillian
Member #12,426
December 2010
|
I'm not sure of its because both threads are trying to access it or because this from the libcurl manual: curl_global_init - This function is not thread safe. You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. This doesn't just mean no other thread that is using libcurl. Because curl_global_init() calls functions of other libraries that are similarly thread unsafe, it could conflict with any other thread that uses these other libraries. Software Engineer by day, hacker by night. |
Audric
Member #907
January 2001
|
As I understand it, it's even simpler than that: Call it once during the global initialization of your program. Long before you start creating extra threads. |
|
1
2
|