众所周知,C ++中的一种高级语言指令(例如“ counter ++”)将被翻译成若干汇编语言指令。
我的问题是单个汇编语言指令呢?某些汇编语言指令也将被翻译成硬件可以直接读取的几条机器指令,这是真的吗?
如果为正,则在发生线程/进程调度时,是否确实在CPU完成执行其当前机器指令后立即进行上下文切换(或在调度过程中需要完成其他工作),即使还有几条指令形成一条汇编语言指令与当前指令一起?
例如,一个汇编语言指令A可以被翻译成机器指令a1,a2,a3。可以在a2,a3之间进行上下文切换吗?
单个汇编语言指令A的相应机器指令:
a1(已执行)a2(正在执行..)<---即将发生下一个上下文切换a3(尚未执行)<---我能够在下一个上下文切换之前执行吗?
我的猜测是a3将不会执行,因为硬件仅知道其机器指令并且不知道汇编语言。因此,每条指令是分开执行的。我对吗?
注意:我要求的是Microsoft Visual C ++ 2008上的实现定义的行为(在2005+上可能是相同的)。操作系统:Win7的简体中文安装。
当我执行带w的非ASCII I / O时,这让我感到惊讶printf。例如
// This won't be necessary as it's the system default code page.
//system("chcp 936");
// NULL to show current locale, which is "C"
printf ("%s\n", setlocale(LC_ALL, NULL));
printf ("?\n");
printf ("%s\n", setlocale(LC_ALL, "English"));
printf ("?\n");
Run Code Online (Sandbox Code Playgroud)
输出:
Active code page: 936
C
?
English_United States.1252
?D
Run Code Online (Sandbox Code Playgroud)
调试器中的内存占用量显示"?"已编码为两个字节:0xD6,,0xD0这是简体中文的代码页936中该字符的代码点。它不应该是在代码点范围的"C" locale其中,最有可能的是0x0 ~ 0x7F。
题:
为什么仍可以在“ C”语言环境中正确显示字符?因此,我猜测语言环境与否无关printf?但是,我想问一问,为什么更改为"English"与936不同的语言环境时,它仍不能显示?有趣? …
我有一个功能:
// string is a null-terminated char array. Replace all a in the string with b
void ReplaceCharInString(char *string, char a, char b)
{
// loop over the string char by char, to find all "a"s and replace them with "b"
}
Run Code Online (Sandbox Code Playgroud)
我在做防守编程.问题是客户端上的实现回复真正传递了一系列字符.如果传入单个字符的地址,程序肯定会遇到错误的状态(可能崩溃).我该如何检查并避免这种情况?(我知道如果我传入std :: string对象,问题就会消失)
我正在阅读遗留的C++代码,其中内存屏障定义如下.主要操作系统是linux和vxworks.编译器是gcc(WindRiver的gcc).
#if((KCompilerGNU)||(kCompilerWindRiver))
#define MEMORY_BARRIER __asm__ volatile("nop\n");
#else
#define MEMORY_BARRIER __asm nop;
#endif
Run Code Online (Sandbox Code Playgroud)
但我不知道无操作操作如何产生内存屏障?或者它只是一个错误实现?
我们知道OoOE 处理器可以对两条指令重新排序。例如,有两个全局变量在不同线程之间共享。
int data;
bool ready;
Run Code Online (Sandbox Code Playgroud)
写入器线程生成data并打开一个标志ready以允许读取器使用该数据。
data = 6;
ready = true;
Run Code Online (Sandbox Code Playgroud)
现在,在 OoOE 处理器上,这两条指令可以重新排序(指令获取、执行)。但是结果的最终提交/写回又如何呢?即,商店秩序井然吗?
据我所知,这完全取决于处理器的内存模型。例如,x86/64 具有强大的内存模型,并且不允许对存储进行重新排序。相反,ARM 通常具有较弱的模型,可能会发生存储重新排序(以及其他几种重新排序)。
另外,直觉告诉我,我是对的,因为否则我们就不需要在典型的多线程程序中使用的这两个指令之间的存储屏障。
但是,我们的维基百科是这样说的:
.. 在上面的概述中,OoOE 处理器避免了当指令由于丢失数据而没有完全准备好处理时,顺序处理器的步骤(2)中发生的停顿。
OoOE 处理器及时用其他准备好的指令填充这些“槽”,然后在最后对结果重新排序,使指令看起来像是正常处理的。
我很困惑。是说结果必须按顺序写回来吗?真的,在 OoOE 处理器中,可以存储data并ready重新排序吗?
引用自C++ 03 2.2字符集:
"基本执行字符集和基本执行宽字符集应各自包含基本源字符集的所有成员.执行字符集成员的值是实现定义的,并且任何其他成员都是语言环境 - 具体."
据此'A',属于执行字符集,其值是实现定义的.所以它不是65('A'十进制的ASCII码),什么?!
// Not always 65?
printf ("%d", 'A');
Run Code Online (Sandbox Code Playgroud)
或者我对执行字符集中的字符值有误解?
在下面的代码中,我期望调用A的构造函数,然后是A的复制构造函数.然而,事实证明只有构造函数被调用.
// MSVC++ 2008
class A
{
public:
A(int i):m_i(i)
{
cout << "constructor\n";
}
A(const A& a)
{
m_i = a.m_i;
cout << "copy constructor\n";
}
private:
int m_i;
};
int main()
{
// only A::A() is called
A a = 1;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我猜编译器是足够聪明的优化掉了第二个电话,来初始化对象一个直接的构造.那么它是标准定义的行为还是只是实现定义的?
我正在阅读Win32中的多线程应用程序一书
该书说return node->next将被编译成单独的机器指令,这些指令不会作为原子操作执行,因此Next()也应该受到关键部分的保护.
我的问题是,它可以转化为什么指令,导致竞争条件?
typedef struct _Node
{
struct Node *next;
int data;
} Node;
typedef struct _List
{
Node *head;
CRITICAL SECTION critical_sec;
} List;
List *CreateList()
{
List *pList = malloc(sizeof(List));
pList->head = NULL;
InitializeCriticalSection(&pList->critical_sec);
return pList;
}
void DeleteList(List *pList)
{
DeleteCriticalSection(&pList->critical_sec);
free(pList);
}
void AddHead(List *pList, Node *node)
{
EnterCriticalSection(&pList->critical_sec);
node->next = pList->head;
pList->head = node;
LeaveCriticalSection(&pList->critical_sec);
}
void Insert(List *pList, Node *afterNode, Node *newNode)
{
EnterCriticalSection(&pList->critical_sec);
if (afterNode == …Run Code Online (Sandbox Code Playgroud) 虽然我用C++编写了这个例子,但是这个代码重构问题也适用于支持OO的任何语言,例如Java.
基本上我有A级
class A
{
public:
void f1();
void f2();
//..
private:
m_a;
};
void A::f1()
{
assert(m_a);
m_a->h1()->h2()->GetData();
//..
}
void A::f2()
{
assert(m_a);
m_a->h1()->h2()->GetData();
//..
}
Run Code Online (Sandbox Code Playgroud)
你们会创建一个m_f持有指针的新私有数据成员m_a->h1()->h2()吗?我能看到的是它有效地消除了多级函数调用,这确实简化了代码.
但从另一个角度来看,它创建了一个"不必要的"数据成员,可以从另一个现有的数据成员中推断出来m_a,这有点多余?
我刚刚陷入两难境地.到目前为止,我无法说服自己使用一个而不是另一个.
你有哪些人喜欢,有什么理由吗?
我正在研究编译器优化(特别是这里的指令重新排序)可能对多线程程序产生的影响.
假设我们有一个读者线程和一个写作者线程.
// Global shared data between threads
bool data;
bool flag = false;
// writer.cpp
void writer()
{
data = true; // (1)
flag = true; // (2)
}
// reader.cpp
void reader()
{
if (flag)
{
count << data;
}
}
Run Code Online (Sandbox Code Playgroud)
可能符合C++ 11标准的编译器重命令指令(1)和(2)?
根据C++"as-if"规则,转换不应该改变程序的可观察行为.显然,在编译编写器时,编译器通常不能确定是否重新排序(1)并且是否(2)会改变程序的可观察行为,因为data并且flag它们都是可能影响另一个线程的可观察行为的全局变量.
但它在此声明可以发生这种重新排序,请参阅编译时的内存排序.
那么我们需要(1)和之间的编译屏障(2)吗?(我很清楚可能的CPU重新排序.这个问题仅适用于编译器重新排序)
c++ ×9
c ×2
c++11 ×1
console ×1
constructor ×1
locale ×1
mbcs ×1
oop ×1
processor ×1
refactoring ×1
visual-c++ ×1
winapi ×1