DWORD WINAPI Fun1Proc(
LPVOID lpParameter // thread data
)
{
while(TRUE)
{
WaitForSingleObject(hMutex,INFINITE);
if(tickets>0)
{
cout<<"thread1 sell ticket : "<<tickets--<<endl;
}
else
break;
ReleaseMutex(hMutex);
cout << "1 released" << endl;
}
return 0;
}DWORD WINAPI Fun2Proc(
LPVOID lpParameter // thread data
)
{
while(TRUE)
{
WaitForSingleObject(hMutex,INFINITE);
if(tickets>0)
{
cout<<"thread2 sell ticket : "<<tickets--<<endl;
}
else
break;
ReleaseMutex(hMutex);
cout << "2 released" << endl;
}
return 0;
}为什么每次都release两次?多线程c++互斥对象
LPVOID lpParameter // thread data
)
{
while(TRUE)
{
WaitForSingleObject(hMutex,INFINITE);
if(tickets>0)
{
cout<<"thread1 sell ticket : "<<tickets--<<endl;
}
else
break;
ReleaseMutex(hMutex);
cout << "1 released" << endl;
}
return 0;
}DWORD WINAPI Fun2Proc(
LPVOID lpParameter // thread data
)
{
while(TRUE)
{
WaitForSingleObject(hMutex,INFINITE);
if(tickets>0)
{
cout<<"thread2 sell ticket : "<<tickets--<<endl;
}
else
break;
ReleaseMutex(hMutex);
cout << "2 released" << endl;
}
return 0;
}为什么每次都release两次?多线程c++互斥对象
另外线程函数中break之前也需要释放互斥量
#include <iostream.h>DWORD WINAPI Fun1Proc(
LPVOID lpParameter // thread data
);DWORD WINAPI Fun2Proc(
LPVOID lpParameter // thread data
);
int index=0;
int tickets=90;
HANDLE hMutex;
void main()
{
HANDLE hThread1;
HANDLE hThread2;
hMutex=CreateMutex(NULL,TRUE,"tickets");
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2); if(hMutex)
{
if(ERROR_ALREADY_EXISTS==GetLastError())
{
cout<<"only one instance can run!"<<endl;
return;
}
}
WaitForSingleObject(hMutex,INFINITE);
ReleaseMutex(hMutex);
ReleaseMutex(hMutex); Sleep(6000);
}DWORD WINAPI Fun1Proc(
LPVOID lpParameter // thread data
)
{
while(TRUE)
{
WaitForSingleObject(hMutex,INFINITE);
if(tickets>0)
{
cout<<"thread1 sell ticket : "<<tickets--<<endl;
}
else
break;
ReleaseMutex(hMutex);
cout << "1 released" << endl;
} return 0;
}DWORD WINAPI Fun2Proc(
LPVOID lpParameter // thread data
)
{
while(TRUE)
{
WaitForSingleObject(hMutex,INFINITE);
if(tickets>0)
{
cout<<"thread2 sell ticket : "<<tickets--<<endl;
}
else
break;
ReleaseMutex(hMutex);
cout << "2 released" << endl;
}
return 0;
}
以上就是完整的代码,就是孙鑫第十五章的程序,我在release后面多加了一条cout语句而已。
http://bbs.csdn.net/topics/390535912
中回答了 , 还 不 结贴。
“互斥”与“临界区”,如果不涉及进程间的同步,从程序逻辑的层面上来看,它们之间的区别不是很大。不同的编译器、不同的运行环境,都会影响执行的结果。比如在我的机器上,会出现
"thread1 sell ticket : 12
1 released
thread1 sell ticket : 11
1 released
thread1 sell ticket : 10
1 released
2 released "
ReleaseMutex(hMutex);
ReleaseMutex(hMutex); 此处
Sleep(6000);
楼主为什么要释放两遍互斥量???
“互斥”与“临界区”,如果不涉及进程间的同步,从程序逻辑的层面上来看,它们之间的区别不是很大。不同的编译器、不同的运行环境,都会影响执行的结果。比如在我的机器上,会出现
"thread1 sell ticket : 12
1 released
thread1 sell ticket : 11
1 released
thread1 sell ticket : 10
1 released
2 released "
嗯。我师兄也是说凑巧这回事。是和单CPU,多CPU也有关系吧
给我的感觉是
WaitForSingleObject(hMutex,INFINITE);
ReleaseMutex(hMutex);
ReleaseMutex(hMutex);
这三行多余!
更重要的是你没有关闭互斥量,应该把这三行去掉,在Sleep(6000);后面加上closehandle(hMutex);
原因是主线程并不需要获得互斥量,他并没有和其他的线程使用共享资源,也就是说他不需要同步,按照你写的代码的话
WaitForSingleObject(hMutex,INFINITE); //获得互斥两
ReleaseMutex(hMutex); //把获得的互斥量释放掉
ReleaseMutex(hMutex);//再次释放互斥两,但没有获得怎么释放呢??会出问题吧。
不是吧。主线程的两个release都是因为主线程先创建了互斥对象,并且CreateMutex函数的第二个参数为TRUE,即互斥对象一开始被创建的时候就和主线程关联了,互斥对象内部的计数器加1。所以主线程必须要release掉才行。第二个release是因为主线程等待互斥对象,而此时互斥对象就已经和主线程关联着呢。所以互斥对象内部的计数器又加1,变成了2.所以release两次没有错的呀。不过我也觉得那三行貌似是多余。不,是那两行。
#include <iostream.h>
DWORD WINAPI Fun1Proc(
LPVOID lpParameter // thread data
);
DWORD WINAPI Fun2Proc(
LPVOID lpParameter // thread data
);
int index=0;
int tickets=90;
HANDLE hMutex;
void main()
{
HANDLE hThread1;
HANDLE hThread2;
hMutex=CreateMutex(NULL,TRUE,"tickets");
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
if(hMutex)
{
if(ERROR_ALREADY_EXISTS==GetLastError())
{
cout<<"only one instance can run!"<<endl;
return;
}
}
// WaitForSingleObject(hMutex,INFINITE);
// ReleaseMutex(hMutex);
ReleaseMutex(hMutex);
Sleep(6000);
}
DWORD WINAPI Fun1Proc(
LPVOID lpParameter // thread data
)
{
while(TRUE)
{
WaitForSingleObject(hMutex,INFINITE);
if(tickets>0)
{
cout<<"thread1 sell ticket : "<<tickets--<<endl;
ReleaseMutex(hMutex);
}
else{
ReleaseMutex(hMutex);
break;
}
cout << "1 released" << endl;
}
return 0;
}
DWORD WINAPI Fun2Proc(
LPVOID lpParameter // thread data
)
{
while(TRUE)
{
WaitForSingleObject(hMutex,INFINITE);
if(tickets>0)
{
cout<<"thread2 sell ticket : "<<tickets--<<endl;
ReleaseMutex(hMutex);
}
else{
ReleaseMutex(hMutex);
break;
}
cout << "2 released" << endl;
}
return 0;
}同志们,请问这个结果又该怎么解释啊?还是很迷糊啊
当然不是这段代码也没关系,两个线程release后的代码执行的时候是随机的,不受控制,给你的建议是:
if(tickets>0)
{
cout<<"thread1 sell ticket : "<<tickets--<<endl;
cout << "1 released" << endl;
ReleaseMutex(hMutex);
}
else{
cout << "1 released" << endl;
ReleaseMutex(hMutex);
break;
}
// cout << "1 released" << endl;
也就是在每一个release之前输出这句话。release之后输出是不可控制的。
当然不是这段代码也没关系,两个线程release后的代码执行的时候是随机的,不受控制,给你的建议是:
if(tickets>0)
{
cout<<"thread1 sell ticket : "<<tickets--<<endl;
cout << "1 released" << endl;
ReleaseMutex(hMutex);
}
else{
cout << "1 released" << endl;
ReleaseMutex(hMutex);
break;
}
// cout << "1 released" << endl;
也就是在每一个release之前输出这句话。release之后输出是不可控制的。
嗯。我试过了在release之前cout,是没有问题的。可为什么release之后cout就不可控制了呢?
WaitForSingleObject(hMutex,INFINITE);
·····
······//代码段
······
ReleaseMutex(hMutex);
这段代码在宏观上是原子性操作的,也就是说进入到WaitForSingleObject(hMutex,INFINITE);之后就要一直执行的releaseMutex();你可以这么理解但微观上不是这样的,而且在执行这段代码的时候也是会切换走的,就算切换走他也只能执行互斥量之外的代码。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#include <windows.h>
#include <io.h>
#else
#include <unistd.h>
#include <sys/time.h>
#include <pthread.h>
#define CRITICAL_SECTION pthread_mutex_t
#define _vsnprintf vsnprintf
#endif
//Log{
#define MAXLOGSIZE 20000000
#define MAXLINSIZE 16000
#include <time.h>
#include <sys/timeb.h>
#include <stdarg.h>
char logfilename1[]="MyLog1.log";
char logfilename2[]="MyLog2.log";
static char logstr[MAXLINSIZE+1];
char datestr[16];
char timestr[16];
char mss[4];
CRITICAL_SECTION cs_log;
FILE *flog;
#ifdef WIN32
void Lock(CRITICAL_SECTION *l) {
EnterCriticalSection(l);
}
void Unlock(CRITICAL_SECTION *l) {
LeaveCriticalSection(l);
}
#else
void Lock(CRITICAL_SECTION *l) {
pthread_mutex_lock(l);
}
void Unlock(CRITICAL_SECTION *l) {
pthread_mutex_unlock(l);
}
#endif
void LogV(const char *pszFmt,va_list argp) {
struct tm *now;
struct timeb tb; if (NULL==pszFmt||0==pszFmt[0]) return;
_vsnprintf(logstr,MAXLINSIZE,pszFmt,argp);
ftime(&tb);
now=localtime(&tb.time);
sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday);
sprintf(timestr,"%02d:%02d:%02d",now->tm_hour ,now->tm_min ,now->tm_sec );
sprintf(mss,"%03d",tb.millitm);
printf("%s %s.%s %s",datestr,timestr,mss,logstr);
flog=fopen(logfilename1,"a");
if (NULL!=flog) {
fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr);
if (ftell(flog)>MAXLOGSIZE) {
fclose(flog);
if (rename(logfilename1,logfilename2)) {
remove(logfilename2);
rename(logfilename1,logfilename2);
}
} else {
fclose(flog);
}
}
}
void Log(const char *pszFmt,...) {
va_list argp; Lock(&cs_log);
va_start(argp,pszFmt);
LogV(pszFmt,argp);
va_end(argp);
Unlock(&cs_log);
}
//Log}
int main(int argc,char * argv[]) {
int i;
#ifdef WIN32
InitializeCriticalSection(&cs_log);
#else
pthread_mutex_init(&cs_log,NULL);
#endif
for (i=0;i<10000;i++) {
Log("This is a Log %04d from FILE:%s LINE:%d\n",i, __FILE__, __LINE__);
}
#ifdef WIN32
DeleteCriticalSection(&cs_log);
#else
pthread_mutex_destroy(&cs_log);
#endif
return 0;
}
//1-78行添加到你带main的.c或.cpp的那个文件的最前面
//81-85行添加到你的main函数开头
//89-93行添加到你的main函数结束前
//在要写LOG的地方仿照第87行的写法写LOG到文件MyLog1.log中
#include <stdio.h>int index=0;volatile int tickets=100;HANDLE g_hMutex=0;
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
while(tickets >0 )
{
WaitForSingleObject(g_hMutex,INFINITE);
tickets--;
printf("thread 1 sell ticket : %d\r\n", tickets);
while((tickets %2) == 1)
{
printf("Wait thread 2 be scheduled\r\n");
ReleaseMutex(g_hMutex);
Sleep(0);
}
}
//
return 0;
}
DWORD WINAPI Fun2Proc( LPVOID lpParameter)
{
while(tickets >0 )
{
WaitForSingleObject(g_hMutex,INFINITE);
tickets--;
printf("thread 2 sell ticket : %d\r\n", tickets);
while((tickets %2) == 0)
{
printf("Wait thread 1 be scheduled\r\n");
ReleaseMutex(g_hMutex);
Sleep(0);
}
}
return 0;
}void main()
{
HANDLE hThread1;
HANDLE hThread2;
//
g_hMutex = CreateMutex(NULL,TRUE,"tickets");
ReleaseMutex(g_hMutex);
//
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
//
CloseHandle(hThread1);
CloseHandle(hThread2);
while (tickets > 0 );
}
99 开始 要 检查 偶数。
不是 问题 的 重点 !
所以 一个线程 可以 被调度 一次,然后 又被调度,。现在线程程中有 同步 代码:
while((tickets %2) == 1) // 奇偶 数
{
printf("Wait thread 2 be scheduled\r\n");
ReleaseMutex(g_hMutex);
Sleep(0);
}
所以出现 等待 多次。互斥 只是说 ,你用 我 不能用,我用 你 不能 用。
不保证:我用我还用, 你用你还用即 00,11,01,10, 4 个状态 互斥只表示 10,01
PS:
可能cout<<"thread2 sell ticket : "<<tickets--<<endl;
这种输入输出,本来就是同步的
不然,不会输出的这么整齐。
你的程序只要一个线程退出,就会造成,互斥量死锁,
如果不执行ReleaseMutex(hMutex);当线程1的时间片到了,CPU也会强制让线程1终止啊,那也会强制的将互斥量的状态变为可用的吧?所以不执行这句,应该也不会死锁的吧。
没有执行虽然,会执行线程切换,hMutex 依然不可用。
时间到,只会让系统有机会检查,是否有其他线程可以运行。不是一定会运行其它线程。
任何一个正在等待资源,
而没有到达 1)等到资源,2) 等待超时 3) 等待出错(本例中 hMutex已经不存在了)
3 个条件之一的线程
始终没有机会运行。
时间片只是系统调度的一个手段。时间到,系统重新安排一个线程,在某个内核上运行
---可能是同一个线程,也可能是其他线程----Windows 的 调度和运行单位是线程,
进程只是线程的容器。所以,一个线程停止运行,不一定安排进程中的其它线程运行,整个系统中的所有线程,按照优先级和状态,完全挂起的不调度(等待中或者睡眠中),只有就绪的---上次调度暂时挂起,只要重新调度就可以立即运行的---,和进入就绪的
-- 睡眠时间到,等到资源,等待出错,等待超时,等等待已经完成的 --的参与调度。优先级高的先运行,界面线程优先级,可能获得一些动态提高;
长期没有运行的,也可能获得,暂时的动态提高。当线程1的时间片到了,CPU也会强制让线程1终止啊,
这种事情是不会出现的;时间片到了,系统会切换到调度程序,开始新的一轮线程调度,而不是强制线程退出。被切换的线程,要么下一轮仍然运行;
要么让出CPU,以便别的线程运行,而自己会被系统挂起。强制退出,必须调用API函数。
线程以下情况退出:
1)抛出一个异常,没有被捕获
2)双重异常,处理捕获异常时,又抛出异常。(这个地方只是个大概,具体情况记不大清楚了)
3)被强制退出,其他位置调用TerminateThread。
4)线程自己调用API----比如ExitThread 等函数;
以及 _endthread,_endthreadex等库函数,会间接调用ExitThread等API 退出。
5)线程自然结束--线程函数返回。一般我们都希望,线程自然结束,这样的代码不会出一点问题。否则,会有一大堆,让人头痛的问题要处理。