以下是主要代码的示例(“Library / stack.h”并不重要,但无论如何,它是this previous question of mine中包含的最后一个来源):
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <tinythread.h>
#include "Library/stack.h"
using namespace std;
using namespace tthread;
#define BOULDERspd 100
// ========================================================================= //
struct Coord {
int x, y;
};
int randOneIn (float n) {
return ((int) (n * (rand() / (RAND_MAX + 1.0))));
}
int randOneIn (int n) {
return ((int) ((float) n * (rand() / (RAND_MAX + 1.0))));
}
// ========================================================================= //
#include <windows.h>
void gotoxy (int column, int line) {
if ((column >= 0) && (line >= 0)) {
COORD coord;
coord.X = column;
coord.Y = line;
SetConsoleCursorPosition(
GetStdHandle( STD_OUTPUT_HANDLE ),
coord
);
}
}
void gotoxy (Coord pos) {
gotoxy(pos.x, pos.y);
}
// ========================================================================= //
void render (char image, Coord pos) {
gotoxy(pos);
cout << image;
}
void unrender (Coord pos) {
gotoxy(pos);
cout << ' ';
}
// ========================================================================= //
char randimage (void) {
return (rand() % 132) + 123;
}
mutex xylock;
class Boulder {
char avatar;
Coord pos;
public:
Boulder (int inix) {
pos.x = inix;
pos.y = 0;
avatar = randimage();
};
void fall (void) {
unrender(pos);
pos.y++;
render(avatar, pos);
Sleep(BOULDERspd);
};
void live (void) {
do {
fall();
} while (y() < 20);
die();
};
void die (void) {
unrender(pos);
pos.y = 0;
};
int x (void) { return pos.x; };
int y (void) { return pos.y; };
};
// ========================================================================= //
class thrStack: public Stack<thread*> {
public:
thrStack (): Stack<thread*> () { };
void pushNrun (thread* elem) {
push(elem);
top->core->joinable();
}
};
void randBoulder (void* arg) {
srand(time(NULL));
Boulder boulder(rand() % 40);
boulder.live();
}
void Boulders (void* arg) {
srand(time(NULL));
thrStack stack;
do {
stack.pushNrun(new thread (randBoulder, 0));
Sleep(rand() % 300);
} while(1);
}
// ========================================================================= //
// ========================================================================= //
int main() {
thread raining (Boulders, 0);
raining.join();
}
我是多线程的新手,所以,为了摆弄它,我正在尝试制作一个程序,使随机字符不断从屏幕顶部掉落,好像它正在下雨的ASCII符号。
然而,我注意到我的编码中有一点(大)错误:
bool xylock = false;
class Boulder {
char avatar;
Coord pos;
public:
Boulder (int inix) {
pos.x = inix;
pos.y = 0;
avatar = randimage();
};
void fall (void) {
unrender(pos);
pos.y++;
render(avatar, pos);
Sleep(BOULDERspd);
};
void live (void) {
do {
fall();
} while (y() < 20);
die();
};
void die (void) {
unrender(pos);
pos.y = 0;
};
int x (void) { return pos.x; };
int y (void) { return pos.y; };
};
因为fall()函数使用gotoxy来改变'全局游标',所以多次调用gotoxy会搞乱程序的预期执行。如果你试图按原样编译代码,你就会得到掉落的字母,不断切换位置并留下自己的垃圾。
有没有办法只使用TinyThread为这个和未来的情况使用或实现锁定?一般来说,在C ++中实现锁的逻辑是什么?
编辑:修改了fall();没关系,Caribou?
void fall (void) {
lock_guard<mutex> guard(xylock);
unrender(pos);
pos.y++;
render(avatar, pos);
xylock.unlock();
Sleep(BOULDERspd);
};
答案 0 :(得分:1)
您可以使用tinythread lib:
http://tinythreadpp.bitsnbites.eu/doc/
具体查看lock_guard
和mutex
对gotoxy的多次调用会搞乱预期的执行 程序。如果你试图按原样编译代码,你就会堕落 不断切换位置并留下垃圾的字母 他们自己身后。
创建一个mutex
对象进行同步,然后在您希望线程安全的函数中使用它创建一个本地lock_guard
。此mutex
也可以使用lock_guard
。
答案 1 :(得分:1)
这里我创建了一个没有框架或类的非常基本的线程示例。正如您所看到的,线程化和同步化不是C ++的工作,而是OS工作! ; - )
这里我创建了一个简单的线程函数,我调用了两次。线程写入相同的变量,但不能同时执行,因此必须保护它。在此示例中,我使用CRITICAL_SECTION对象将变量锁定一个线程。如果一个线程锁定它,另一个线程无法访问它,必须等到它空闲。
仔细看看,我也保护了printf操作。如果你不这样做会怎么样?你会得到一个非常有趣的外包!找出原因并了解线程和锁的工作原理。 :-)
#include <windows.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include <process.h>
//a global variable (just do do someting):
int g_ThreadCounter = 0;
//global variable to end the threads:
bool g_Run = true;
//do not use global variables, there are better solutions! I just did it here to
//keep it simple and focus on the issue!
//a critical section object - something like a "soft-version" of a mutex to synchronize
//write access on variables
CRITICAL_SECTION critical;
//a thread function
unsigned __stdcall threadFunc(void *pThreadNum)
{
unsigned int iThreadNum = reinterpret_cast<unsigned int>(pThreadNum);
do{
//you need the critical section only when you change values:
EnterCriticalSection(&critical);
g_ThreadCounter++;
printf("from thread: ");
printf("%d", iThreadNum);
printf(" counter = ");
printf("%d", g_ThreadCounter);
printf("\n");
LeaveCriticalSection(&critical);
//sleep a secound
Sleep (1000);
}while(g_Run);
_endthreadex(0);
return 0;
}
int main()
{
unsigned int ThreadID1 = 1;
unsigned int ThreadID2 = 2;
//initialize the critical section with spin count (can be very effective in case
//of short operation times, see msdn for more information)
if(!InitializeCriticalSectionAndSpinCount(&critical, 1000))
{
//DO NOT START THE THREADS, YOU DON'T HAVE SYNCHRONISATION!!!
printf("someting went wrong, press any key to exit");
//do some error handling
getchar();
exit(-1);
}
//start the threads
HANDLE thHandle1 = (HANDLE)_beginthreadex(NULL, 0, &threadFunc, (void*) ThreadID1, 0, NULL);
HANDLE thHandle2 = (HANDLE)_beginthreadex(NULL, 0, &threadFunc, (void*) ThreadID2, 0, NULL);
if(thHandle1 == INVALID_HANDLE_VALUE || thHandle2 == INVALID_HANDLE_VALUE)
{
printf("something went wrong, press any key to exit");
//do some error handling
getchar();
exit(-1);
}
//the main thread sleeps while the other threads are working
Sleep(5000);
//set the stop variable
EnterCriticalSection(&critical);
g_Run = false;
LeaveCriticalSection(&critical);
//wait for the thread; infinite means, you wait as long as the
//thread takes to finish
WaitForSingleObject(thHandle1, INFINITE);
CloseHandle(thHandle1);
WaitForSingleObject(thHandle2, INFINITE);
CloseHandle(thHandle2);
DeleteCriticalSection(&critical);
printf("press any key to exit");
getchar();
return 0;
}
研究您正在使用的操作系统!它有时比对框架和外国课程过分关注更好。这可以解决很多问题!