输出tickets每次减1的值,用线程1,线程2切换输出,并且使用了临界区来限制线程对于tickets的访问,但是输出的时候线程1没有办法进入tickets的使用权
#include<stdio.h>
#include<process.h>
#include<windows.h>
int tickets=50;
CRITICAL_SECTION g_cs;
unsigned int __stdcall Fun1(VOID *lp)
{
while(true)
{
EnterCriticalSection(&g_cs);
Sleep(1);
if(tickets>0)
{
printf("thread1 %d\n",tickets--);
LeaveCriticalSection(&g_cs);
}
else
{
LeaveCriticalSection(&g_cs);
break;
}
}
}
unsigned int __stdcall Fun2(VOID *lp)
{
while(true)
{
EnterCriticalSection(&g_cs);
Sleep(1);
if(tickets>0)
{
printf("thread1 %d\n",tickets--);
LeaveCriticalSection(&g_cs);
}
else
{
LeaveCriticalSection(&g_cs);
break;
}
}
}
int main()
{
HANDLE handle1,handle2;
handle1=(HANDLE)_beginthreadex(NULL,0,Fun1,NULL,0,NULL);
handle2=(HANDLE)_beginthreadex(NULL,0,Fun2,NULL,0,NULL);
CloseHandle(handle1);
CloseHandle(handle2);
InitializeCriticalSection(&g_cs);
Sleep(4000);
DeleteCriticalSection(&g_cs);
return 0;
}
输出
编译器用的codeblocks
你的程序,不是进不了线程2,而是很少能进入线程2(我实验的时候,偶尔能进入,有时开头,有时结尾,有时中间,反正很少),解决你的问题的办法:
把sleep(1)移动到锁的外面。
你的sleep在锁里面,这样,变成处理数据的时候要延时,从性能角度考虑不好。从逻辑考虑:
因为你解锁后,线程马上又进入循环,此时线程2可能还来不及获取锁已经解锁的状态就又被线程1再次锁定了。
谢谢你,我想在问下为什么会出现已停止工作的情况。这段代码是按照vc++深入详解(孙鑫版)但是他的视频里头运行就是正常的是电脑原因?
借用 一楼 简化后的代码:
#include<stdio.h> #include<process.h> #include<windows.h> int tickets=50; CRITICAL_SECTION g_cs; unsigned int __stdcall Fun(VOID *lp) { char *cp = (char *)lp; while(true) { Sleep(1);//很关键,不能放在锁里面,放在锁前锁后没关系,锁前是预处理,锁后是后处理。 //如果锁里的内容是线程处理的全部,那么,这样的过程是不适合使用多线程的 //而你的代码恰巧是处理的全部,从而导致锁的繁忙。 EnterCriticalSection(&g_cs); if(tickets>0) { printf("%s %d\n",cp, tickets--); LeaveCriticalSection(&g_cs); } else { LeaveCriticalSection(&g_cs); break; } } return 0; } int main() { HANDLE handle1,handle2; InitializeCriticalSection(&g_cs); handle1=(HANDLE)_beginthreadex(NULL,0,Fun,"Thread1 ",0,NULL); handle2=(HANDLE)_beginthreadex(NULL,0,Fun,"Thread2 ",0,NULL); WaitForSingleObject(handle1,INFINITE); CloseHandle(handle1); WaitForSingleObject(handle2,INFINITE); CloseHandle(handle2); DeleteCriticalSection(&g_cs); return 0; }
很奇怪的是,我把代码类化,运行报告错误,错误点是加锁的时候,没细研究,如果你能解决,可以告知一下:
#pragma once #include<stdio.h> #include<process.h> #include<windows.h> #define _USERENTRY __stdcall class ThreadTest { private: int tickets = 50; CRITICAL_SECTION g_cs; private: unsigned int __stdcall Fun(VOID *lp); public: ThreadTest(); ~ThreadTest(); public: void Test(); };
#include "ThreadTest.h" ThreadTest::ThreadTest() { } ThreadTest::~ThreadTest() { } void ThreadTest::Test() { HANDLE handle1, handle2; InitializeCriticalSection(&g_cs); union { // 联合类,用于转换类成员方法指针到普通函数指针(试过编译器不允许在这两种函数之间强制转换),不知道有没有更好的方法。 unsigned int (_USERENTRY *ThreadProc)(void *); unsigned int (_USERENTRY ThreadTest::*MemberProc)(void *); } Proc; Proc.MemberProc = &ThreadTest::Fun; handle1 = (HANDLE)_beginthreadex(NULL, 0, Proc.ThreadProc, "Thread1 ", 0, NULL); handle2 = (HANDLE)_beginthreadex(NULL, 0, Proc.ThreadProc, "Thread2 ", 0, NULL); WaitForSingleObject(handle1, INFINITE); CloseHandle(handle1); WaitForSingleObject(handle2, INFINITE); CloseHandle(handle2); DeleteCriticalSection(&g_cs); } unsigned int __stdcall ThreadTest::Fun(VOID *lp) { char *cp = (char *)lp; while (true) { EnterCriticalSection(&g_cs); if (tickets>0) { printf("%s %d\n", cp, tickets--); LeaveCriticalSection(&g_cs); } else { LeaveCriticalSection(&g_cs); break; } Sleep(1); } return 0; }
@calmound: 这个问题好还真的不知道,应该是锁的释放未完成导致的。
我在实验中遇到了异常:
1、中断了main函数
2、直接关闭了控制台窗口(应用窗口)
3、在VS里终止了调试
结果问题出来了:VS卡住了。后来是通过进程管理器把进程关闭,VS才能用起来,但是,进程管理器里的进程却一直关闭失败,现在还在。郁闷呢。
@calmound: 我的实验,在我的电脑上是没报告你这个错误。
我想,你参考下一楼代码的修改,他把锁的初始化放在了前面,而你是在启动线程之后,把这个位置调整下看。
(把锁提前初始化,这个问题即便不受影响也应该有这个习惯)
如果跟这个问题没关系,那就可能是你的电脑或系统的问题了。
InitializeCriticalSection(&g_cs);
handle1=(HANDLE)_beginthreadex(NULL,0,Fun1,NULL,0,NULL);
handle2=(HANDLE)_beginthreadex(NULL,0,Fun2,NULL,0,NULL);
Sleep(4000);
CloseHandle(handle1);
CloseHandle(handle2);
DeleteCriticalSection(&g_cs);
#include<stdio.h>
#include<process.h>
#include<windows.h>
int tickets=50;
CRITICAL_SECTION g_cs;
unsigned int __stdcall Fun(VOID *lp)
{
char *cp = (char *)lp;
while(true) {
EnterCriticalSection(&g_cs);
Sleep(1);
if(tickets>0) {
printf("%s %d\n",cp, tickets--);
LeaveCriticalSection(&g_cs);
} else {
LeaveCriticalSection(&g_cs);
break;
}
}
return 0;
}
int main()
{
HANDLE handle1,handle2;
InitializeCriticalSection(&g_cs);
handle1=(HANDLE)_beginthreadex(NULL,0,Fun,"Thread1 ",0,NULL);
handle2=(HANDLE)_beginthreadex(NULL,0,Fun,"Thread2 ",0,NULL);
WaitForSingleObject(handle1,INFINITE);
CloseHandle(handle1);
WaitForSingleObject(handle2,INFINITE);
CloseHandle(handle2);
DeleteCriticalSection(&g_cs);
return 0;
}
这样是不是会简洁很多呢
你好,我想问下我那个哪里错了?为什么无法运行
@calmound: InitializeCriticalSection(&g_cs);你的g_cs没有初始化,这是很关键的。
其次,与你这个出错没有关系的一个问题是,不要等待线程运行结束不要用sleep,正确的是WaitForSingleObject
@calmound: 我也看了下你在三楼的另外的代码,很成问题
@calmound: 如果要设计成类,一般 InitializeCriticalSection(&g_cs);在类的构造函数,或者说初始化函数,DeleteCriticalSection(&g_cs);在类的析构函数,或者说摧毁函数。而线程的运行函数unsigned int __stdcall Fun(VOID *lp);应该设计成static函数,这样就与对象无关,可以用类名访问。看见你和三楼两个不懂多线程的讨论,呵呵