• Civilization 7 has been announced. For more info please check the forum here .

Why I use multiThread in DLL but it is not work?

I have introduced multi-thread method in Game, however it is not work wel. Sometimes it may lead to exe crash. Why?
The CPU load implies that it acutal use 2 cores to work. But the data is not update in GET_PLAYER((PlayerTypes)i)
If I write GET_PLAYER((PlayerTypes)i).doTurn() , it will crash.
 
C++:
# CvGlobals.cpp
#include <stdio.h>
#include <time.h>


#include <Windows.h>
#include <iostream>

// 线程池数量
HANDLE threadPools[1];

// CVGLOBAL全局数据锁
int* CvGlobalNewThread0_isThisGameTurn = new int[100];





DWORD WINAPI CvGlobals::CvGlobalNewThread0(LPVOID lpParam) {

    CvGlobals* pThis = (CvGlobals*)lpParam;
    int i;
    // 线程执行的代码
    // pThis->debug();

    while (true) {

        // 异步更新AI_updateFoundValues
        if (CvGlobalNewThread0_isThisGameTurn[0] == 1) {
            // pThis->calculatePIandAdd();

            // 1为异步调用
            if (GC.CVGLOBAL_MULTITHREAD_AI_FOUNDVALUE == 1) {
                for (i = 0; i < MAX_PLAYERS; i++) {
                    GET_PLAYER((PlayerTypes)i).AI_updateFoundValues();
                }
            }

            // it will crash during the game
            // GET_PLAYER((PlayerTypes)i).doTurn();

            CvGlobalNewThread0_isThisGameTurn[0] = 0;
        }





        Sleep(100);
    }


}



void CvGlobals::initThread() {
    // 多线程开关
    if (GC.CVGLOBAL_USE_MULTITHREAD > 0) {
        threadPools[0] = CreateThread(NULL, 0, CvGlobalNewThread0, this, 0, NULL);
        // threadPools[1] = CreateThread(NULL, 0, CvGlobalNewThread1, this, 0, NULL);
    }
}



// 游戏每回合执行的函数
void CvGlobals::doTurn() const {
    CvGlobalNewThread0_isThisGameTurn[0] = 1;
    CvGlobalNewThread0_isThisGameTurn[1] = 1;
    doTurnCore();
}
 
I have introduced multi-thread method in Game, however it is not work wel. Sometimes it may lead to exe crash. Why?
The CPU load implies that it acutal use 2 cores to work. But the data is not update in GET_PLAYER((PlayerTypes)i)
If I write GET_PLAYER((PlayerTypes)i).doTurn() , it will crash.
The exe was not written to handle multiple threads, which means any calls to the exe should be done with locks to make sure only one thread can call the exe at any time. Also the DLL itself isn't thread safe. GC.getGameINLINE().getSorenRandNum stores the seed you generated and will use it to generate the next one. This means the order of calls matter and if you have a network game, then you need to call in the same order or the game will go out of sync.

As for using multiple threads, We The People use Intel's Thread Building Blocks (TBB). Supposedly this has a bunch of features, which makes it easier to spread the load evenly on all CPU cores. And yes it isn't limited to just Intel CPUs.
The newest version doesn't work with vc7.1, but there is an older version in WTP, which does work. It does however have the tradeoff that tbb.dll and tbbmalloc.dll has to be in the same folder as the exe file. It's possible that we might be able to fix that limitation at some point (we have a plan, which might work, but it takes time).
 
The exe was not written to handle multiple threads, which means any calls to the exe should be done with locks to make sure only one thread can call the exe at any time. Also the DLL itself isn't thread safe. GC.getGameINLINE().getSorenRandNum stores the seed you generated and will use it to generate the next one. This means the order of calls matter and if you have a network game, then you need to call in the same order or the game will go out of sync.

As for using multiple threads, We The People use Intel's Thread Building Blocks (TBB). Supposedly this has a bunch of features, which makes it easier to spread the load evenly on all CPU cores. And yes it isn't limited to just Intel CPUs.
The newest version doesn't work with vc7.1, but there is an older version in WTP, which does work. It does however have the tradeoff that tbb.dll and tbbmalloc.dll has to be in the same folder as the exe file. It's possible that we might be able to fix that limitation at some point (we have a plan, which might work, but it takes time).
Yes I found that when I use function in Game(Such as GC.getGame()) it is not safe in multi-thread.
Multi-Thread program is really difficult in C++( I am a Java programmer, it is more easy in Java) And it is much more defficult in C++ 2003 (Because there are not std::thread in C++ 2003),
Considering the Civ4.EXE is not designed for multi-thread , it is much more difficult to use multi-thread in CvGameCore.dll
Is TBB works better than the boost::thread in vc 7.1? I found boost::thread is used in an older version of Caveman2Cosmos, and it is removed now.
 
The exe was not written to handle multiple threads, which means any calls to the exe should be done with locks to make sure only one thread can call the exe at any time. Also the DLL itself isn't thread safe. GC.getGameINLINE().getSorenRandNum stores the seed you generated and will use it to generate the next one. This means the order of calls matter and if you have a network game, then you need to call in the same order or the game will go out of sync.

As for using multiple threads, We The People use Intel's Thread Building Blocks (TBB). Supposedly this has a bunch of features, which makes it easier to spread the load evenly on all CPU cores. And yes it isn't limited to just Intel CPUs.
The newest version doesn't work with vc7.1, but there is an older version in WTP, which does work. It does however have the tradeoff that tbb.dll and tbbmalloc.dll has to be in the same folder as the exe file. It's possible that we might be able to fix that limitation at some point (we have a plan, which might work, but it takes time).
I simply read some code in Caveman2Cosmos and WTP, I found multi-thread are limited used under TBB.
is TBB can only use in single function such as Path-finding? Or TBB can be used in CvPlayer::doTurn() or CvPlot::doTurn()?
 
is TBB can only use in single function such as Path-finding? Or TBB can be used in CvPlayer::doTurn() or CvPlot::doTurn()?
It can be used just like any other threads. The reason why it's not used more than it is is because the code is generally not thread safe. This means it takes some effort to make it thread safe, particularly if it also has to be network sync safe. This is an issue with threads in general and not specific to TBB.

Having said that, the most CPU demanding task is pathfinding (at least on WTP sized maps), which can take more CPU time than all other AI tasks combined. For this reason TBB was added to handle pathfinding and if it handles anything else, then it's a bonus. It does handle moving colonists around inside cities, but that's a colonization only CPU issue.

Is TBB works better than the boost::thread in vc 7.1? I found boost::thread is used in an older version of Caveman2Cosmos, and it is removed now.
TBB works better when there are more jobs than hardware threads. The reason C2C removed the thread system is that they used to have lag and adding another thread would make it less visible. However they got rid of it because the slow code has been rewritten to make the game even faster than when it was multithreaded. As I recall, they did have issues with the multithreaded part, so getting rid of it was welcome.

Once again it shows that just adding more threads to slow code is not always the right answer. Single core performance boosts should be checked out first. Having said that, there are tasks where more cores will always be better. There is no simple rule on what to do because the best solution always depends on the task.
 
It can be used just like any other threads. The reason why it's not used more than it is is because the code is generally not thread safe. This means it takes some effort to make it thread safe, particularly if it also has to be network sync safe. This is an issue with threads in general and not specific to TBB.

Having said that, the most CPU demanding task is pathfinding (at least on WTP sized maps), which can take more CPU time than all other AI tasks combined. For this reason TBB was added to handle pathfinding and if it handles anything else, then it's a bonus. It does handle moving colonists around inside cities, but that's a colonization only CPU issue.


TBB works better when there are more jobs than hardware threads. The reason C2C removed the thread system is that they used to have lag and adding another thread would make it less visible. However they got rid of it because the slow code has been rewritten to make the game even faster than when it was multithreaded. As I recall, they did have issues with the multithreaded part, so getting rid of it was welcome.

Once again it shows that just adding more threads to slow code is not always the right answer. Single core performance boosts should be checked out first. Having said that, there are tasks where more cores will always be better. There is no simple rule on what to do because the best solution always depends on the task.
Thanks a lot, it helps me a lot because I am not a professional C++ programmer. My main code language is Java and Python, if I am not a Civ4 modder, probably I will not write a line of C++ code.
 
@mediv01
I replied to you in a different thread but I wanted to chip in with my opinion concerning multithreading civ4.

My position is that you'll have to carefully profile the execution profile of civ4 to determine if it would make sense to multithread at all. From what I've gathered from profiling K-Mod and AdvCiv is that there is currently a very limited potential for multithreading to be of any benefit.
 
Top Bottom