volatile到底有没有用?
第一次认识到这个关键字是在KeilC里写51单片机的程序,发现中断程序和主程序不能正常使用同一个全局变量。后来用了这个关键字也不行。(定时器改变全局变量,主程序根据全局变...
第一次认识到这个关键字是在Keil C里写51单片机的程序,发现中断程序和主程序不能正常使用同一个全局变量。后来用了这个关键字也不行。(定时器改变全局变量,主程序根据全局变量改变引脚电平——另外说一下,IO口变量,就是P0、P1什么的,是不需要volatile也能用来通信的。但是谁也不会浪费一个IO口来做中断通信变量。)
第二次写中断程序时,没用这个关键字,却奇迹般地与主程序成功用一个全局结构体变量实现通信。可能是第二次设置了大内存模式吧,估计在xdata里面不区分主程序和中断程序。(定时器和串口发送消息到消息队列,然后主程序扫瞄处理消息,并改变引脚电平。)
第三次用visual studio 2010写win32控制台程序,不管是debug还是release都不需要volatile。(串口多线程实验,另一端用的是虚拟串口,网上下载的串口代码,自己写的多线程类。成员变量就是通信变量。)
所以我怀疑这个关键字可能不是多线程用的。刚查到还有一种多进程的编程方式,感觉多进程更不可能会用这个关键字。
具体程序已经不重要了,成功的已经成功了,失败的程序我也删掉了。只是想问,有没有老鸟能给解释一下,什么情况下多线程和中断程序不需要volatile、什么情况下需要volatile、什么情况下就算有了volatile也没用。
注:我一次也没有用上volatile
部分visual studio 2010代码:
#define BkThreadFunctionTypeForBeginThreadEx(Function) \ unsigned ( __stdcall Function)(void * pParam)
typedef unsigned ( __stdcall*BkThreadFunctionTypeForBeginThreadEx)( void * pParam );//宏定义和类型声明中重复使用相同的关键字好像并不相互影响,所以就不要研究这个了。
class CBkThread{ friend BkThreadFunctionTypeForBeginThreadEx(BkThreadFunctionTypeForBeginThreadExManager);
HANDLE m_hBkThread;
unsigned m_nThreadID;
volatile bool m_bIsSuspended;
BkThreadFunctionTypeForBeginThreadEx m_BkFun;
/*volatile*/ int */*volatile*/ m_nCmd; /*volatile*/ int */*volatile*/ m_nRet;
const size_t m_nCmdLength;//可能有部分编译器不支持构造函数中初始化常量,const关键字必要时可去除 const size_t m_nRetLength;
/*volatile*/ size_t m_nCmdIn; /*volatile*/ size_t m_nCmdOut;
/*volatile*/ size_t m_nRetIn;
/*volatile*/ size_t m_nRetOut;
void IncIndex(size_t &nIndex,size_t const&nMaxSize){const size_t &&nMaxIndex=nMaxSize-1;++nIndex;nIndex&=nMaxIndex;}
public: volatile int m_nSignIn;//为将来做准备,本次实验并不用到这个变量。
volatile int m_nSignOut;//同上
//六个传递消息的函数,操作Cmd和Ret两条队列。 bool PushCmd(int nCmd); bool PushRet(int nRet);
bool PopCmd();
bool PopRet();
bool GetFirstCmd(int &nCmd,bool const & bReadyPop=1);
bool GetFirstRet(int &nRet,bool const & bReadyPop=1);
……(其它直接操作线程的函数)
};
具体的读线程和写线程如下:
CWinComm是网络上下载的串口代码重新封装了一下。当时是直接printf();输出的,并没有线程间通信的问题。后来我把它改成线程通信的方式了。
CWinComm com3(L"COM3");
BkThreadFunctionTypeForBeginThreadEx(MyThread1)/*DWORD WINAPI MyThread1(LPVOID pParam)*/{
::CBkThread *pBT=(CBkThread*)pParam;
char RXBuff;
for(;;){
if(com3.Read(&RXBuff)){
if(pBT->PushRet(RXBuff));
//printf("%c",RXBuff);
}//if
}//for
return 0;
}//MyThread1
BkThreadFunctionTypeForBeginThreadEx(MyThread2)/*DWORD WINAPI MyThread2(LPVOID pParam)*/{
while(com3.GetComm()!=INVALID_HANDLE_VALUE){
unsigned char d;
d=getch();
printf("%c",d);
com3.Write(&d);
}//while
return 0;
}//MyThread2 展开
第二次写中断程序时,没用这个关键字,却奇迹般地与主程序成功用一个全局结构体变量实现通信。可能是第二次设置了大内存模式吧,估计在xdata里面不区分主程序和中断程序。(定时器和串口发送消息到消息队列,然后主程序扫瞄处理消息,并改变引脚电平。)
第三次用visual studio 2010写win32控制台程序,不管是debug还是release都不需要volatile。(串口多线程实验,另一端用的是虚拟串口,网上下载的串口代码,自己写的多线程类。成员变量就是通信变量。)
所以我怀疑这个关键字可能不是多线程用的。刚查到还有一种多进程的编程方式,感觉多进程更不可能会用这个关键字。
具体程序已经不重要了,成功的已经成功了,失败的程序我也删掉了。只是想问,有没有老鸟能给解释一下,什么情况下多线程和中断程序不需要volatile、什么情况下需要volatile、什么情况下就算有了volatile也没用。
注:我一次也没有用上volatile
部分visual studio 2010代码:
#define BkThreadFunctionTypeForBeginThreadEx(Function) \ unsigned ( __stdcall Function)(void * pParam)
typedef unsigned ( __stdcall*BkThreadFunctionTypeForBeginThreadEx)( void * pParam );//宏定义和类型声明中重复使用相同的关键字好像并不相互影响,所以就不要研究这个了。
class CBkThread{ friend BkThreadFunctionTypeForBeginThreadEx(BkThreadFunctionTypeForBeginThreadExManager);
HANDLE m_hBkThread;
unsigned m_nThreadID;
volatile bool m_bIsSuspended;
BkThreadFunctionTypeForBeginThreadEx m_BkFun;
/*volatile*/ int */*volatile*/ m_nCmd; /*volatile*/ int */*volatile*/ m_nRet;
const size_t m_nCmdLength;//可能有部分编译器不支持构造函数中初始化常量,const关键字必要时可去除 const size_t m_nRetLength;
/*volatile*/ size_t m_nCmdIn; /*volatile*/ size_t m_nCmdOut;
/*volatile*/ size_t m_nRetIn;
/*volatile*/ size_t m_nRetOut;
void IncIndex(size_t &nIndex,size_t const&nMaxSize){const size_t &&nMaxIndex=nMaxSize-1;++nIndex;nIndex&=nMaxIndex;}
public: volatile int m_nSignIn;//为将来做准备,本次实验并不用到这个变量。
volatile int m_nSignOut;//同上
//六个传递消息的函数,操作Cmd和Ret两条队列。 bool PushCmd(int nCmd); bool PushRet(int nRet);
bool PopCmd();
bool PopRet();
bool GetFirstCmd(int &nCmd,bool const & bReadyPop=1);
bool GetFirstRet(int &nRet,bool const & bReadyPop=1);
……(其它直接操作线程的函数)
};
具体的读线程和写线程如下:
CWinComm是网络上下载的串口代码重新封装了一下。当时是直接printf();输出的,并没有线程间通信的问题。后来我把它改成线程通信的方式了。
CWinComm com3(L"COM3");
BkThreadFunctionTypeForBeginThreadEx(MyThread1)/*DWORD WINAPI MyThread1(LPVOID pParam)*/{
::CBkThread *pBT=(CBkThread*)pParam;
char RXBuff;
for(;;){
if(com3.Read(&RXBuff)){
if(pBT->PushRet(RXBuff));
//printf("%c",RXBuff);
}//if
}//for
return 0;
}//MyThread1
BkThreadFunctionTypeForBeginThreadEx(MyThread2)/*DWORD WINAPI MyThread2(LPVOID pParam)*/{
while(com3.GetComm()!=INVALID_HANDLE_VALUE){
unsigned char d;
d=getch();
printf("%c",d);
com3.Write(&d);
}//while
return 0;
}//MyThread2 展开
1个回答
展开全部
当然有用了,定义了个x变量,如果不用voliate申明的话,搞不好被其他什么地方修改了都不知道,用voliae申明的话,在你的程序里这个值不变的!
更多追问追答
追问
就是说用了volatile以后,每次操作相当于复制了一个临时副本,然后只对临时副本操作,而没有volatile就是直接操作这个变量了?可是这个功能使用子函数的形参就可以实现了,没必要专门搞出一个关键字啊。
关键是我的程序里用不用这个感觉都差不多。
追答
平时用不到的,在嵌入式里面用到的比较多,获取引脚信号什么的,其他地方用不到
AiPPT
2024-12-03 广告
2024-12-03 广告
作为北京饼干科技有限公司的一员,对于市场上各类工具都有所了解。就AiPPT而言,它确实为用户提供了便捷高效的PPT制作体验。通过智能化的辅助功能,用户能够快速生成专业且富有创意的演示文稿,极大地节省了时间和精力。无论是对于个人用户还是企业团...
点击进入详情页
本回答由AiPPT提供
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询