多线程模拟"等待-通知"模型,有时崩溃,求解

weichen2005 2008-08-18 03:51:32
// event1.cpp : Defines the entry point for the console application.
//

// test cases:
// send threads: 2, per thread: 10
// send threads: 20, per thread: 100
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <iomanip>
#include <list>

using namespace std;

//MyPool g_pool;

///////////////////////////////////////////////////////////////////////////////
class MyMutex {
public:
MyMutex();
~MyMutex();
int Lock();
int UnLock();
private:
HANDLE m_object;
};

MyMutex::MyMutex() {
cout << "MyMutex::MyMutex" << endl;
m_object = ::CreateMutex(NULL, FALSE, NULL);
}
MyMutex::~MyMutex() {
cout << "MyMutex::~MyMutex" << endl;
::CloseHandle(m_object);
}
int MyMutex::Lock() {
return (::WaitForSingleObject(m_object, INFINITE) == WAIT_FAILED) ? -1 : 0;
}
int MyMutex::UnLock() {
return (::ReleaseMutex(m_object) == 0) ? -1 : 0;
}
///////////////////////////////////////////////////////////////////////////////
class MyClass {
public:
MyClass(int id);
~MyClass();
int GetID();
private:
int m_id;
};

MyClass::MyClass(int id) {
m_id = id;
}
MyClass::~MyClass() {
}
int MyClass::GetID() {
return m_id;
}
///////////////////////////////////////////////////////////////////////////////
extern MyMutex g_FileLock;
class MyPool {
public:
MyPool();
~MyPool();
MyClass* Get();
void Put(MyClass* p);
private:
list<MyClass*> m_list;
HANDLE m_event;
MyMutex m_lock;
};

MyPool::MyPool() {
cout << "MyPool::MyPool" << endl;
//m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
m_event = ::CreateEvent(NULL, FALSE, FALSE, NULL);
}
MyPool::~MyPool() {
cout << "MyPool::~MyPool" << endl;
::CloseHandle(m_event);
}
MyClass* MyPool::Get() {
MyClass* ret;
DWORD dwRet = -1;
DWORD tid = GetCurrentThreadId();

re:
m_lock.Lock();
while (m_list.size()==0) {
g_FileLock.Lock();
cout << "Thread(" << setw(4) <<tid<<") " << "no node now, waitting... ..." << endl;
g_FileLock.UnLock();
// simulation of pthread_cond_wait
m_lock.UnLock();
//::Sleep(1000);
dwRet = ::WaitForSingleObject(m_event, INFINITE);
if (dwRet==WAIT_OBJECT_0) {
g_FileLock.Lock();
cout <<"Thread(" <<tid<<") " "success return from wait function" << endl;
g_FileLock.UnLock();
goto re;
}
}
ret = *(m_list.begin());
m_list.pop_front();

/*
if (m_list.size()==0) {
m_lock.UnLock();
return NULL;
}
ret = *(m_list.begin());
m_list.pop_front();*/

m_lock.UnLock();

return ret;
}
void MyPool::Put(MyClass* p) {
m_lock.Lock();

m_list.push_back(p);
::SetEvent(m_event);

/*m_list.push_back(p);*/

m_lock.UnLock();
}
///////////////////////////////////////////////////////////////////////////////
MyPool g_pool;

MyMutex g_FileLock;

DWORD WINAPI put_thread(LPVOID arg);
DWORD WINAPI get_thread(LPVOID arg);

DWORD WINAPI put_thread(LPVOID arg) {
int *p = (int*)arg;
DWORD tid = ::GetCurrentThreadId();

int base = *p * 100;
//for (int i=0; i<10; ++i) {
for (int i=base; i<base+100; ++i) {
MyClass* tmp = new MyClass(i);
g_pool.Put(tmp);
g_FileLock.Lock();
cout << "Thread(" <<tid<<") "<<"put::" << i << endl;
g_FileLock.UnLock();
}

delete p;
return 0;
}

DWORD WINAPI get_thread(LPVOID arg) {
DWORD tid = ::GetCurrentThreadId();
while (1) {
MyClass* tmp = g_pool.Get();
if (tmp == NULL) {
g_FileLock.Lock();
cout <<"Thread(" <<tid<<") "<< "no data find" << endl;
g_FileLock.UnLock();
::Sleep(1000);
continue;
}
int i = tmp->GetID();
g_FileLock.Lock();
cout << "Thread(" <<tid<<") "<<"get::" << i << endl;
g_FileLock.UnLock();
delete tmp;
}
}

//MyPool g_pool;

int main(int argc, char* argv[])
{
//MyMutex MyLock;
HANDLE get_thd[20];
HANDLE put_thd[10];
DWORD dwThreadId;

int* tag=NULL;

// put threads, about 64 max threads count
// for (int i=0; i<2000; ++i) { // cant create too much threads

//for (int i=0; i<2; ++i) {
//for (int i=0; i<20; ++i) {
for (int i=0; i<1; ++i) {
tag = new int(i);
put_thd[i] = CreateThread(
NULL, // default security attributes
0, // use default stack size
put_thread, // thread function
(LPVOID)tag, // argument to thread function
0, // use default creation flags
&dwThreadId); // returns the thread identifier
if (put_thd[i] == NULL) {
g_FileLock.Lock();
fprintf(stderr, "Thread(main) create put thread(%d) error\n", i);
g_FileLock.UnLock();
} else {
g_FileLock.Lock();
fprintf(stderr, "Thread(main) create put thread(%d) success\n", i);
g_FileLock.UnLock();
}
}

// get threads
//for (i=0; i<5; ++i) {
for (i=0; i<3; ++i) {
get_thd[i] = CreateThread(
NULL, // default security attributes
0, // use default stack size
get_thread, // thread function
NULL, // argument to thread function
0, // use default creation flags
&dwThreadId); // returns the thread identifier
if (get_thd[i] == NULL) {
g_FileLock.Lock();
fprintf(stderr, "Thread(main) create get thread(%d) error\n", i);
g_FileLock.UnLock();
} else {
g_FileLock.Lock();
fprintf(stderr, "Thread(main) create get thread(%d) success\n", i);
g_FileLock.UnLock();
}
}

while (1) ::Sleep(1000);

return 0;
}
///////////////////////////////////////////////////////////////////////////////
...全文
112 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
andylin02 2008-11-14
  • 打赏
  • 举报
回复
哎,没有记住的教训!
害苦了我,两天尽在想怎么崩溃在stl里面呢?

谢谢楼主分享:)

andylin
weichen2005 2008-09-19
  • 打赏
  • 举报
回复
原来是vc的连接多线程库的问题: 默认情况下vc连接的是"Single-thread debug dll", 这种情况下
的new / delete不是线程安全的, 修改工程选项使之连接"Multi-thread debug dll" 就没有问题了
... ...

此问题至少在10天之内毫无解决思路, 2周以后才逐步想到这方面, 可见软件开发的复杂性不是人们可以
想象的, 以此做个记录... ...
zzultc 2008-08-30
  • 打赏
  • 举报
回复
我觉得你可以这样改进一下:
每个线程要执行的函数,刚开始就加锁,等到离开时再解锁。这样防止执行到某个函数中,被切换到其他的线程中去。
不要为了多执行几行代码,把逻辑搞得很复杂,那样很容易出错。
weichen2005 2008-08-19
  • 打赏
  • 举报
回复
诸位windows开发高手帮帮忙吧,兄弟我搞不定了。。。

15,466

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧