I recently upgraded some projects from VS2013 to VS2015 and I have found some problems with my threaded code. The issue seems to be that a thread that is waiting on a mutex to get unlocked is not getting control when another thread unlocks the mutex. Since the other thread is a loop that locks the mutex, does something, then unlocks it, the result is that thread running the loop many times and the other thread waiting >10sec for control. Below is a very small sample program that reproduces the bug for me.
#include "stdafx.h"
#include <thread>
#include <mutex>
#include <iostream>
std::mutex print_guard_;
int i = 0;
void RenderLoop()
{
while (true) {
print_guard_.lock();
std::cout << "Render: " << i << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
print_guard_.unlock();
std::this_thread::yield();
}
}
void Print()
{
print_guard_.lock();
std::cout << "Main Thread: " << i << std::endl;
print_guard_.unlock();
}
int main()
{
std::thread* thread_ = new std::thread(RenderLoop);
while (true) {
Print();
}
return 0;
}
The error occurs both with and without the yield command in the RenderLoop function. In Visual Studio 2015 I get something like:
Render: 0
Render: 0
Render: 0
Render: 0
Render: 0
Render: 0
Render: 0
Render: 0
Render: 0
... (continues for a few seconds or longer)
Main Thread: 0
Main Thread: 0
Main Thread: 0
Main Thread: 0
Main Thread: 0
Main Thread: 0
Render: 0
Render: 0
Render: 0
...
and on VS2013 I get
Render: 0
Main Thread: 0
Render: 0
Main Thread: 0
Render: 0
Main Thread: 0
Render: 0
Main Thread: 0
Render: 0
Main Thread: 0
Render: 0
Main Thread: 0
Render: 0
Main Thread: 0
Render: 0
Main Thread: 0
Render: 0
Main Thread: 0
Render: 0
Main Thread: 0
Render: 0
Main Thread: 0
Anyone have any ideas on how to force the thread to give up control?
Related
This is my code
#include <pthread.h>
#include <stdio.h>
void cleanup(void *arg) {
printf("cleanup: %s\n", (const char*)arg);
}
void *thr_fn1(void *arg) {
printf("thread 1 strat\n");
pthread_cleanup_push(cleanup, (void*)"thread 1 first handler");
pthread_cleanup_push(cleanup, (void*)"thread 1 first handler");
if(arg)
return (void*)1;
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
return (void*)1;
}
void *thr_fn2(void *arg) {
printf("thread 2 strat\n");
pthread_cleanup_push(cleanup, (void*)"thread 2 first handler");
pthread_cleanup_push(cleanup, (void*)"thread 2 first handler");
if(arg)
return (void*)2;
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
return (void*)2;
}
int main() {
int err;
pthread_t tid1, tid2;
void *tret;
pthread_create(&tid1, NULL, thr_fn1, (void*)1);
pthread_create(&tid2, NULL, thr_fn2, (void*)1);
pthread_join(tid1, &tret);
printf("pthread 1 exit code %ld\n", tret);
pthread_join(tid2, &tret);
printf("pthread 2 exit code %ld\n", tret);
return 0;
}
Now I run it using gcc and g++
$ gcc main.c -o main
$ ./main
thread 2 strat
thread 1 strat
pthread 1 exit code 1
pthread 2 exit code 2
$ g++ main.c -o main
$ ./main
thread 1 strat
cleanup: thread 1 first handler
cleanup: thread 1 first handler
thread 2 strat
cleanup: thread 2 first handler
cleanup: thread 2 first handler
pthread 1 exit code 1
pthread 2 exit code 2
$
Why they behave differently?
Any other functions behave like this?
I found the implementations of gcc and g++ are different. So which one is a better implementation?
On Linux, the pthread_cleanup_push() and pthread_cleanup_pop() functions are implemented as macros that expand to text containing { and }, respectively.
# define pthread_cleanup_push(routine, arg) \
do { \
__pthread_cleanup_class __clframe (routine, arg)
If compiled with g++, __pthread_cleanup_class is a C++ class:
#ifdef __cplusplus
/* Class to handle cancellation handler invocation. */
class __pthread_cleanup_class
{
void (*__cancel_routine) (void *);
void *__cancel_arg;
int __do_it;
int __cancel_type;
public:
__pthread_cleanup_class (void (*__fct) (void *), void *__arg)
: __cancel_routine (__fct), __cancel_arg (__arg), __do_it (1) { }
~__pthread_cleanup_class () { if (__do_it) __cancel_routine (__cancel_arg); }
void __setdoit (int __newval) { __do_it = __newval; }
void __defer () { pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED,
&__cancel_type); }
void __restore () const { pthread_setcanceltype (__cancel_type, 0); }
};
It behaves like any class, its destructor runs on scope end.
In C, using gcc, cleanup handlers require pthread_exit(), but your code does return.
When a thread terminates by calling pthread_exit(3), all clean-up handlers are executed as described in the preceding point. (Clean-up handlers are not called if the thread terminates by performing a return from the thread start function.)
Hello I am trying to create a script to save/load my custom Weapon Layout for my game.
The save function works fine, but if I want load the layout, it crash my game.
I know where the problem is, but idk how to fix these, so I need your knowledge!
void SaveWeaponsLayout()
{
Ini wpLayout = (".\\Files\\Settings\\WeaponsLayout.ini");
Log::Msg("Reading Data for WeaponsLayout.ini!");
Player playerPed = PLAYER::PLAYER_PED_ID();
if (!ENTITY::IS_ENTITY_DEAD(playerPed))
{
for (auto & wpID : weaponLayoutList)
{
Hash weapon = wpID.weaponHash;
char * wpName = wpID.WeaponName;
if (WEAPON::HAS_PED_GOT_WEAPON(playerPed, wpID.weaponHash, 0))
{
int weaponInHex = weapon;
std::string weaponInHex_ = hexify< int >(weaponInHex);
wpLayout.WriteString(weaponInHex_, wpName, "WEAPONHASH");
}
for (auto & wpCompID : weaponComponentList)
{
Hash weaponComp = wpCompID.weaponCompHash;
char * wpCompName = wpCompID.weaponComponent;
if (WEAPON::HAS_PED_GOT_WEAPON_COMPONENT(playerPed, wpID.weaponHash, wpCompID.weaponCompHash))
{
int weaponCompInHex = weaponComp;
std::string weaponCompInHex_ = hexify< int >(weaponCompInHex);
wpLayout.WriteString(weaponCompInHex_, wpName, wpCompName);
}
}
}
}
Log::Msg("Files WeaponsLayout.ini created!");
Notifications::MessageCentre6000("~p~Saved~s~: Weapons Layout");
}
The list where I get the Weapon Data from the game >>
static struct wpList
{
__int64 weaponHash;
char * WeaponName;
};
static std::vector<wpList> weaponLayoutList{
//{ 0xA2719263, "Unarmed" },
{ 0xFBAB5776, "Parachute" },
{ 0x99B507EA, "Knife" },
{ 0x8BB05FD7, "Flashlight" },
{ 0xCD274149, "Battle Axe" },
{ 0x94117305, "Pool Cue" },
...
}; // 88x Weapons
The list where I get the Weapon Components Data from the game >>
static struct wpCompList
{
unsigned int weaponCompHash;
char * weaponComponent;
};
static std::vector<wpCompList> weaponComponentList{
{ 0x75414F30, "COMPONENT_AT_RAILCOVER_01" },
{ 0x0C164F53, "COMPONENT_AT_AR_AFGRIP" },
{ 0x359B7AAE, "COMPONENT_AT_PI_FLSH" },
{ 0x7BC4CDDC, "COMPONENT_AT_AR_FLSH" },
{ 0x9D2FBF29, "COMPONENT_AT_SCOPE_MACRO" },
...
}; // 551x Weapon Components
This is the WeaponsLayout.ini what I have saved!
[Micro SMG]
WEAPONHASH=0x13532244
COMPONENT_AT_PI_FLSH=0x359b7aae
COMPONENT_AT_AR_SUPP_02=0xa73d4664
COMPONENT_MICROSMG_CLIP_02=0x10e6ba2b
[Assault Rifle]
WEAPONHASH=0xbfefff6d
COMPONENT_ASSAULTRIFLE_CLIP_03=0xdbf0a53d
[Advanced Rifle]
WEAPONHASH=0xaf113f99
COMPONENT_AT_AR_FLSH=0x7bc4cddc
COMPONENT_ADVANCEDRIFLE_CLIP_01=0xfa8fa10f
[Pump Shotgun]
WEAPONHASH=0x1d073a89
COMPONENT_AT_AR_FLSH=0x7bc4cddc
COMPONENT_AT_SR_SUPP=0xe608b35e
COMPONENT_PUMPSHOTGUN_CLIP_01=0xd16f1438
COMPONENT_PUMPSHOTGUN_VARMOD_LOWRIDER=0xa2d79ddb
...so now my script what make me problems, because it search in my file for all Weapons & Weapon Components!
void LoadWeaponsLayout()
{
Log::Msg("Files reading WeaponsLayout.ini!");
Ini wpLayout = (".\\Files\\Settings\\WeaponsLayout.ini");
Player playerPed = PLAYER::PLAYER_PED_ID();
if (!ENTITY::IS_ENTITY_DEAD(playerPed))
{
for (auto wpID : weaponLayoutList)
{
char * wpName = wpID.WeaponName;
unsigned weaponX = wpLayout.GetInt(wpName, "WEAPONHASH");
if (!WEAPON::HAS_PED_GOT_WEAPON(playerPed, weaponX, 0))
{
WEAPON::GIVE_DELAYED_WEAPON_TO_PED(playerPed, weaponX, 9999, 0);
for (auto wpCompID : weaponComponentList)
{
char * wpCompoName = wpCompID.weaponComponent;
unsigned weaponComp = wpLayout.GetInt(wpName, wpCompoName);
WAIT(0);
if (WEAPON::DOES_WEAPON_TAKE_WEAPON_COMPONENT(weaponX, weaponComp))
{
WEAPON::GIVE_WEAPON_COMPONENT_TO_PED(playerPed, weaponX, weaponComp);
}
}
}
}
}
Log::Msg("Files WeaponsLayout.ini loaded!");
Notifications::MessageCentre4000("~p~Loaded~s~: Weapons Layout");
}
[my ini class]
class Ini
{
private:
std::string inifile;
public:
Ini(std::string file)
{
this->inifile = file;
}
void WriteString(std::string string, std::string app, std::string key)
{
WritePrivateProfileStringA(app.c_str(), key.c_str(), string.c_str(), this->inifile.c_str());
}
std::string GetString(std::string app, std::string key)
{
char buf[100];
GetPrivateProfileStringA(app.c_str(), key.c_str(), "NULL", buf, 100, this->inifile.c_str());
return (std::string)buf;
}
void WriteInt(int value, std::string app, std::string key)
{
WriteString(std::to_string(value), app, key);
}
int GetInt(std::string app, std::string key)
{
return std::stoi(GetString(app, key));
}
}
DEBUG:
Files reading WeaponsLayout.ini!
Exception thrown at 0x000007FEFD71A06D in GTA5.exe: Microsoft C++ exception: std::invalid_argument at memory location 0x000000013AD4E610.
The thread 0x4628 has exited with code 0 (0x0).
The thread 0x4d78 has exited with code 0 (0x0).
The thread 0x4cd0 has exited with code 0 (0x0).
The thread 0x3c20 has exited with code 0 (0x0).
The thread 0x3678 has exited with code 0 (0x0).
The thread 0x1278 has exited with code 0 (0x0).
The thread 0x59a0 has exited with code 0 (0x0).
The thread 0x5458 has exited with code 0 (0x0).
The thread 0x4a8c has exited with code 0 (0x0).
The thread 0x5300 has exited with code 0 (0x0).
The thread 0x4b20 has exited with code 0 (0x0).
The thread 0x526c has exited with code 0 (0x0).
The thread 0x500c has exited with code 0 (0x0).
The thread 0x4be0 has exited with code 0 (0x0).
The thread 0x266c has exited with code 0 (0x0).
The thread 0x59ec has exited with code 0 (0x0).
The thread 0x3020 has exited with code 0 (0x0).
The thread 0x581c has exited with code 0 (0x0).
The thread 0x5098 has exited with code 0 (0x0).
The thread 0xd98 has exited with code 0 (0x0).
The thread 0x5180 has exited with code 0 (0x0).
The thread 0x1cc8 has exited with code 0 (0x0).
The thread 0x4c84 has exited with code 0 (0x0).
The thread 0x112c has exited with code 0 (0x0).
The thread 0x2dc0 has exited with code 0 (0x0).
The thread 0x5910 has exited with code 0 (0x0).
The thread 0x59cc has exited with code 0 (0x0).
The thread 0x2eb4 has exited with code 0 (0x0).
The thread 0x5aec has exited with code 0 (0x0).
The thread 0x58cc has exited with code 0 (0x0).
The thread 0x5a94 has exited with code 0 (0x0).
The thread 0x481c has exited with code 0 (0x0).
The thread 0x5554 has exited with code 0 (0x0).
The thread 0x2358 has exited with code 0 (0x0).
The thread 0x1b70 has exited with code 0 (0x0).
The thread 0x5764 has exited with code 0 (0x0).
The thread 0x53cc has exited with code 0 (0x0).
The thread 0x4ba4 has exited with code 0 (0x0).
The thread 0x4008 has exited with code 0 (0x0).
The thread 0x566c has exited with code 0 (0x0).
The thread 0x415c has exited with code 0 (0x0).
The thread 0x4cc0 has exited with code 0 (0x0).
The thread 0x512c has exited with code 0 (0x0).
The thread 0x5614 has exited with code 0 (0x0).
The thread 0x5390 has exited with code 0 (0x0).
The thread 0x4d68 has exited with code 0 (0x0).
The thread 0x56e8 has exited with code 0 (0x0).
The thread 0x54e8 has exited with code 0 (0x0).
The thread 0x1bc0 has exited with code 0 (0x0).
The thread 0x55d0 has exited with code 0 (0x0).
The thread 0x4f1c has exited with code 0 (0x0).
The thread 0x4efc has exited with code 0 (0x0).
The thread 0x54b4 has exited with code 0 (0x0).
The thread 0x4144 has exited with code 0 (0x0).
The thread 0x614 has exited with code 0 (0x0).
The thread 0x5820 has exited with code 0 (0x0).
The thread 0x4878 has exited with code 0 (0x0).
The thread 0x4184 has exited with code 0 (0x0).
The thread 0x2064 has exited with code 0 (0x0).
The thread 0x568c has exited with code 0 (0x0).
The thread 0x30cc has exited with code 0 (0x0).
The thread 0x57d8 has exited with code 0 (0x0).
The thread 0x5658 has exited with code 0 (0x0).
The thread 0x4c94 has exited with code 0 (0x0).
The thread 0x5084 has exited with code 0 (0x0).
The thread 0x4ff4 has exited with code 0 (0x0).
The thread 0x5858 has exited with code 0 (0x0).
The thread 0x148c has exited with code 0 (0x0).
The thread 0x209c has exited with code 0 (0x0).
The thread 0x52bc has exited with code 0 (0x0).
The thread 0x5170 has exited with code 0 (0x0).
The thread 0x1388 has exited with code 0 (0x0).
The thread 0xc10 has exited with code 0 (0x0).
The thread 0x12c0 has exited with code 0 (0x0).
The thread 0xca8 has exited with code 0 (0x0).
The thread 0x2040 has exited with code 0 (0x0).
The thread 0x4d1c has exited with code 0 (0x0).
The thread 0x358c has exited with code 0 (0x0).
The thread 0x1eac has exited with code 0 (0x0).
The thread 0x5608 has exited with code 0 (0x0).
The thread 0x28d8 has exited with code 0 (0x0).
The thread 0x4c44 has exited with code 0 (0x0).
The thread 0x5a0c has exited with code 0 (0x0).
The thread 0x4420 has exited with code 0 (0x0).
The thread 0x5828 has exited with code 0 (0x0).
The thread 0x29f4 has exited with code 0 (0x0).
The thread 0x4e60 has exited with code 0 (0x0).
The thread 0x54c4 has exited with code 0 (0x0).
The thread 0x4564 has exited with code 0 (0x0).
The thread 0x50ec has exited with code 0 (0x0).
The thread 0x43cc has exited with code 0 (0x0).
The thread 0x4e74 has exited with code 0 (0x0).
The thread 0x549c has exited with code 0 (0x0).
The thread 0xd74 has exited with code 0 (0x0).
The thread 0x5b90 has exited with code 0 (0x0).
The thread 0x4f7c has exited with code 0 (0x0).
The thread 0x30e8 has exited with code 0 (0x0).
The thread 0x4f74 has exited with code 0 (0x0).
The thread 0x1530 has exited with code 0 (0x0).
The thread 0x5584 has exited with code 0 (0x0).
DXGI WARNING: Process is terminating. Using simple reporting. Please call ReportLiveObjects() at runtime for standard reporting. [ STATE_CREATION WARNING #0: ]
DXGI WARNING: Live Producer at 0x0000000000474EA8, Refcount: 4. [ STATE_CREATION WARNING #0: ]
DXGI WARNING: Live Object at 0x0000000000488880, Refcount: 4. [ STATE_CREATION WARNING #0: ]
DXGI WARNING: Live Object at 0x00000000004640E0, Refcount: 1. [ STATE_CREATION WARNING #0: ]
DXGI WARNING: Live Object : 2 [ STATE_CREATION WARNING #0: ]
The program '[22656] GTA5.exe' has exited with code 0 (0x0).
During a debugging session, I found a problem that I was able to reduce down to this C++11 code:
#include <thread>
#include <vector>
#include <unordered_map>
class MyClass
{
public:
MyClass(){
printf("%p\n", this);
}
~MyClass(){
printf("~%p\n", this);
}
std::unordered_map<int, int> member;
};
thread_local MyClass threadLocalObject;
int main(){
std::vector<std::thread> threads;
for (int i = 0; i < 40; ++i){
threads.emplace_back([&](){
printf("%ld\n", threadLocalObject.member.size());
});
}
for (auto &thread : threads)
thread.join();
return 0;
}
The compiler I use is g++-6 (Homebrew GCC 6.4.0) 6.4.0 on MacOS 10.12.6.
The problem is that it seems to crash inside the destructor of member.
It doesn't always crash, though, which makes me wonder if it's some kind of race condition between the threads.
Any help is appreciated, this drives me insane.
I had similar crashes with MinGW on Windows, so I really hope to gain some knowledge from someone who understands what is going on here.
This is one of the more drastic crashlogs of this code:
0x7f9b2ba00228
0x7f9b2ac02728
0x7f9b2ba004e8
0x7f9b2ae00128
0x7f9b2b800128
0x7f9b2ad00128
0x7f9b2ac025f8
0x7f9b2ad00178
0x7f9b2b900138
0x7f9b2b800288
0x7f9b2ad002d8
0x7f9b2b900188
0x7f9b2ba00388
0x7f9b2b800548
0x7f9b2b8003e8
0x7f9b2b800cd8
0x7f9b2af00898
0x7f9b2ba00a68
0x7f9b2ae00ad8
0x7f9b2af00c08
0x7f9b2b900918
0x7f9b2ba00dd8
0x7f9b2b801048
0x7f9b2ae00e48
0x7f9b2b8013b8
0x7f9b2b801728
0x7f9b2af00f78
0x7f9b2ba00538
0x7f9b2af012e8
0x7f9b2b9002e8
0x7f9b2af00268
0x7f9b2ae004a8
0x7f9b2b900338
0x7f9b2af003c8
0x7f9b2ae00608
0x7f9b2af00528
0x7f9b2ae00768
0x7f9b2ae008c8
0x7f9b2af00688
0x7f9b2af006d8
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
~0x7f9b2ba00228
0
0
0
0
0
0
0
0
0
0
0
0
~0x7f9b2ac025f8
~0x7f9b2ad00178
~0x7f9b2ad00128
a.out(32726,0x70000e123000) malloc: *** error for object 0xa38333130303962: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
~0x7f9b2b900138
~0x7f9b2ad002d8
a.out(32726,0x70000e2ac000) malloc: *** error for object 0xa38633830306561: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
~0x7f9b2ba00388
~0x7f9b2b800288
~0x7f9b2b800548
~0x7f9b2b8003e8
~0x7f9b2b800cd8
~0x7f9b2af00898
~0x7f9b2ba00a68
~0x7f9b2ae00ad8
~0x7f9b2af00c08
~0x7f9b2b900918
~0x7f9b2ba00dd8
~0x7f9b2ae00e48
~0x7f9b2b801048
~0x7f9b2b8013b8
~0x7f9b2b801728
~0x7f9b2af00f78
~0x7f9b2ba00538
~0x7f9b2af012e8
~0x7f9b2b9002e8
~0x7f9b2ae004a8
~0x7f9b2af00268
~0x7f9b2b900338
~0x7f9b2af003c8
~0x7f9b2ae00608
~0x7f9b2af00528
~0x7f9b2ae00768
~0x7f9b2ae008c8
~0x7f9b2af00688
~0x7f9b2af006d8
~0x7f9b2ac02728
~0x7f9b2ae00128
~0x7f9b2b800128
Illegal instruction: 4
I have problem to share variable from thread1 to thread2 and main.cpp. My variable in thread1 has a name "value". I have shared to thread2 and make an increment in main.cpp. This is my code in thread1.h :
#ifndef THREAD1_H
#define THREAD1_H
#include <QCoreApplication>
#include <QDebug>
class thread1 : public QObject
{
Q_OBJECT
public:
thread1();
void changeValue(int input);
int value;
};
#endif // THREAD1_H
My code in thread1.cpp:
#include "thread1.h"
void thread1::changeValue(int input)
{
if(input > 10 && input < 15)
qDebug() << "hello world 1...";
else if(input > 15 && input < 20)
qDebug() << "Hello world 2...";
}
thread1::thread1()
{
}
My code in thread2.h:
#ifndef THREAD2_H
#define THREAD2_H
#include <QThread>
#include "thread1.h"
class thread2 : public QThread
{
Q_OBJECT
public:
thread2(QObject *parent = 0);
void checkthread1();
private:
thread1 *thr;
};
#endif // THREAD2_H
My code in thread2.cpp:
#include "thread2.h"
void thread2::checkthread1()
{
thr = new thread1();
qDebug() << "thread 1 value from thread2.c = " << QString::number(thr->value);
thr->changeValue(thr->value);
}
thread2::thread2(QObject *parent) : QThread(parent)
{
}
My code in main.cpp:
#include <QCoreApplication>
#include <QTime>
#include <QDebug>
#include "thread1.h"
#include "thread2.h"
//Global Variable
thread2 *thr2;
thread1 *thr1;
void delay(int waited)
{
QTime dieTime = QTime::currentTime().addMSecs(waited);
while(QTime::currentTime() < dieTime)
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
thr1 = new thread1();
thr2 = new thread2();
while(1)
{
thr1->value += 1;
qDebug() << "thread 1 value from main.c = " << QString::number(thr1->value);
thr2->checkthread1();
delay(1000);
}
return a.exec();
}
And my result is:
thread 1 value from main.c = "17"
thread 1 value from thread2.c = "48"
thread 1 value from main.c = "18"
thread 1 value from thread2.c = "0"
thread 1 value from main.c = "19"
thread 1 value from thread2.c = "7143547"
thread 1 value from main.c = "20"
thread 1 value from thread2.c = "0"
thread 1 value from main.c = "21"
thread 1 value from thread2.c = "16"
Hello world 2...
thread 1 value from main.c = "22"
thread 1 value from thread2.c = "56"
thread 1 value from main.c = "23"
thread 1 value from thread2.c = "8"
thread 1 value from main.c = "24"
thread 1 value from thread2.c = "0"
thread 1 value from main.c = "25"
thread 1 value from thread2.c = "0"
thread 1 value from main.c = "26"
thread 1 value from thread2.c = "0"
thread 1 value from main.c = "27"
thread 1 value from thread2.c = "0"
thread 1 value from main.c = "28"
thread 1 value from thread2.c = "48"
thread 1 value from main.c = "29"
thread 1 value from thread2.c = "1818326560"
thread 1 value from main.c = "30"
thread 1 value from thread2.c = "0"
thread 1 value from main.c = "31"
thread 1 value from thread2.c = "16"
Hello world 2...
thread 1 value from main.c = "32"
thread 1 value from thread2.c = "0"
thread 1 value from main.c = "33"
thread 1 value from thread2.c = "0"
"value" in main.cpp make a good increment like what i want. I have desired "value" in thread2.cpp have same value like in main.cpp. But the result give me another value. I'm just little bit confused. Why "value" in thread2.cpp is change?
You seem to still be struggling with the basics, such as keeping track of the objects you have. You claim to have two threads, but that's wrong: you keep creating new threads every time you call checkthread1().
You also fail to call delete, which you should only do after you know a thread has exited.
Since you have so many threads, you're not actually changing the same value. That's causing the problem you see. You'll need an atomic value once you fixed the thread spam
QMutex and other similar, when you use qmutex you guarantee that only one thread at the moment have access to variable. You can see examples on qt documentation site.
threads qt
I created a simple program to measure thread performance. I ripped out portions of a larger program in order to illustrate my point. Hopefully it's not too terrible to read.
Here is the program:
#include <sstream>
#include <thread>
#include <list>
#include <map>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include <string.h>
std::mutex m_totalTranMutex;
int m_totalTrans = 0;
bool m_startThreads = false;
std::condition_variable m_allowThreadStart;
std::mutex m_threadStartMutex;
std::map<int,std::thread::native_handle_type> m_threadNativeHandles;
char *my_strdup(const char *str)
{
size_t len = strlen(str);
char *x = (char *)malloc(len+1);
if(x == nullptr)
return nullptr;
memcpy(x,str,len+1);
return x;
}
void DoWork()
{
char abc[50000];
char *s1, *s2;
std::strcpy(abc, "12345");
std::strcpy(abc+20000, "12345");
s1 = my_strdup(abc);
s2 = my_strdup(abc);
free(s1);
free(s2);
}
void WorkerThread(int threadID)
{
{
std::unique_lock<std::mutex> lk(m_threadStartMutex);
m_allowThreadStart.wait(lk, []{return m_startThreads;});
}
double transPerSec = 1 / 99999;
int transactionCounter = 0;
int64_t clockTicksUsed = 0;
std::thread::native_handle_type handle = m_threadNativeHandles[threadID];
std::chrono::high_resolution_clock::time_point current = std::chrono::high_resolution_clock::now();
std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
std::chrono::high_resolution_clock::time_point end = start + std::chrono::minutes(1);
int random_num_loops = 0;
double interarrivaltime = 0.0;
double timeHolderReal = 0.0;
while(current < end)
{
std::chrono::high_resolution_clock::time_point startWork = std::chrono::high_resolution_clock::now();
for(int loopIndex = 0; loopIndex < 100; ++loopIndex)
{
for(int alwaysOneHundred = 0; alwaysOneHundred < 100; ++alwaysOneHundred)
{
DoWork();
}
}
std::chrono::high_resolution_clock::time_point endWork = std::chrono::high_resolution_clock::now();
++transactionCounter;
clockTicksUsed += std::chrono::duration_cast<std::chrono::milliseconds>(endWork - startWork).count();
current = std::chrono::high_resolution_clock::now();
}
std::lock_guard<std::mutex> tranMutex(m_totalTranMutex);
std::cout << "Thread " << threadID << " finished with " << transactionCounter << " transaction." << std::endl;
m_totalTrans += transactionCounter;
}
int main(int argc, char *argv[])
{
std::stringstream ss;
int numthreads = atoi(argv[1]);
std::list<std::thread> threads;
int threadIds = 1;
for(int i = 0; i < numthreads; ++i)
{
threads.push_back(std::thread(&WorkerThread, threadIds));
m_threadNativeHandles.insert(std::make_pair(threadIds, threads.rbegin()->native_handle()));
++threadIds;
}
{
std::lock_guard<std::mutex> lk(m_threadStartMutex);
m_startThreads = true;
}
m_allowThreadStart.notify_all();
//Join until completion
for(std::thread &th : threads)
{
th.join();
}
ss << "TotalTran" << std::endl
<< m_totalTrans << std::endl;
std::cout << ss.str();
}
Application usage: app N
where app is the name of the application and N is the number of threads to produce. The program runs for 1 minute.
On windows, I build this program with Visual Studio 2012. I execute the program on a quad core I7 (4 cores, 2 threads per core).
I get the following:
simplethread 1
Thread 1 finished with 1667 transaction.
TotalTran
1667
simplethread 2
Thread 1 finished with 1037 transaction.
Thread 2 finished with 1030 transaction.
TotalTran
2067
simplethread 3
Thread 3 finished with 824 transaction.
Thread 2 finished with 830 transaction.
Thread 1 finished with 837 transaction.
TotalTran
2491
simplethread 4
Thread 3 finished with 688 transaction.
Thread 2 finished with 693 transaction.
Thread 1 finished with 704 transaction.
Thread 4 finished with 691 transaction.
TotalTran
2776
simplethread 8
Thread 2 finished with 334 transaction.
Thread 6 finished with 325 transaction.
Thread 7 finished with 346 transaction.
Thread 1 finished with 329 transaction.
Thread 8 finished with 329 transaction.
Thread 3 finished with 338 transaction.
Thread 5 finished with 331 transaction.
Thread 4 finished with 330 transaction.
TotalTran
2662
E:\Development\Projects\Applications\CPUBenchmark\Debug>simplethread 16
Thread 16 finished with 163 transaction.
Thread 15 finished with 169 transaction.
Thread 12 finished with 165 transaction.
Thread 9 finished with 170 transaction.
Thread 10 finished with 166 transaction.
Thread 4 finished with 164 transaction.
Thread 13 finished with 166 transaction.
Thread 8 finished with 165 transaction.
Thread 6 finished with 165 transaction.
Thread 5 finished with 168 transaction.
Thread 2 finished with 161 transaction.
Thread 1 finished with 159 transaction.
Thread 7 finished with 160 transaction.
Thread 11 finished with 161 transaction.
Thread 14 finished with 163 transaction.
Thread 3 finished with 161 transaction.
TotalTran
2626
These numbers look a little poor. I was expecting a lot closer to double going from one thread doing X work to 2 threads doing 2X work on this system. The threads did do about the same amount of work but not as much in one minutes time.
It get's even stranger when I move to solaris.
On Solaris 11, using GCC 4.8.0, I build this program as follows:
gcc -o simple simpleThreads.cpp -I. -std=c++11 -DSOLARIS=1 -lstdc++ -lm
when i run "./simple 1", i get
Thread 1 finished with 19686 transaction.
TotalTran
19686
for "./simple 2", I get:
Thread 1 finished with 5248 transaction.
Thread 2 finished with 2484 transaction.
TotalTran
7732
On Solaris, the 2 thread case is much slower. I can't figure out what I'm doing wrong. I'm new to c++11 constructs and threads. So it's a double whammy. gcc -v shows the thread model is posix. Any help would be appreciated.