This question already has answers here:
for loop missing initialization
(6 answers)
Closed 3 years ago.
I'm new to CS, and found this code online. What does this blank between two semicolons indicate? What's the range of this for loop? Thanks.
for (int i = 0, temp; ; i++)
This is the typical structure of a for loop:
for(initialization; condition ; increment/decrement)
{
statement(s);
}
but yours is as follows:
for(initialization; ; increment)
{
statement(s);
}
As you can see the condition part is removed which is completely valid, but this just means that the loop will run infinitely.
Typically in cases like this, some logic inside the loop block will be responsible to break out of the loop given some condition is met.
If you look at the reference for for at learn.microsoft.com you can see the following example.
The following example defines the infinite for loop:
for ( ; ; )
{
// Body of the loop.
}
The infinity comes from the "the condition section" being empty. Again from the reference:
The condition section, if present, must be a boolean expression. That expression is evaluated before every loop iteration. If the condition section is not present or the boolean expression evaluates to true, the next loop iteration is executed; otherwise, the loop is exited.
Here's a bad clock implemented via a never-ending loop to show the difference between how i and temp change as the loop progresses.
public async static Task Main(string[] args)
{
var start = DateTime.Now;
for (int i = 0, temp; ; i++)
{
// 'i' is a) initalised and b) incremented after each
// 'temp' is a) *un*initialised and b) doesn't automatically change
temp = 666;
Console.WriteLine($"It's now {DateTime.Now.TimeOfDay} and this is about {i} seconds after {start.TimeOfDay}. 'temp' is {temp}");
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
Output:
It's now 09:07:02.9269857 and this is about 0 seconds after 09:07:02.9246017. 'temp' is 666
It's now 09:07:04.0195240 and this is about 1 seconds after 09:07:02.9246017. 'temp' is 666
It's now 09:07:05.0223953 and this is about 2 seconds after 09:07:02.9246017. 'temp' is 666
It's now 09:07:06.0379706 and this is about 3 seconds after 09:07:02.9246017. 'temp' is 666
It's now 09:07:07.0482980 and this is about 4 seconds after 09:07:02.9246017. 'temp' is 666
See the docs for for:
The for statement defines initializer, condition, and iterator sections:
for (initializer; condition; iterator)
body
All three sections are optional.
Also, from the same source:
If the condition section is not present or the boolean expression evaluates to true, the next loop iteration is executed; otherwise, the loop is exited.
(emphasis mine)
Related
I have a somewhat complex procedure that contains nested loop and a subgroupBarrier.
In a simplified form it looks like
while(true){
while(some_condition){
if(end_condition){
atomicAdd(some_variable,1);
debugPrintfEXT("%d:%d",gl_SubgroupID,gl_SubgroupInvocationID.x);
subgroupBarrier();
if(gl_SubgroupInvocationID.x==0){
debugPrintfEXT("Finish! %d", some_variable);
// do some final stuff
}
return; // this is the only return in the entire procedure
}
// do some stuff
}
// do some stuff
}
Overall the procedure is correct and it does what's expected from it. All subgroup threads
always eventually reach the end condition. However, in my logs I see
0:2
0:3
0:0
Finish! 3
0:1
And it's not just the matter of logs being displayed out of order. I perform atomic addition and it seems to be wrong too. I need all threads to finish all their atomic operations before printing Finish!. If the subgroupBarrier() worked correctly, it should print 4, but in my case it prints 3. I've been mostly following this tutorial
https://www.khronos.org/blog/vulkan-subgroup-tutorial
and it says that
void subgroupBarrier() performs a full memory and execution barrier - basically when an invocation returns from subgroupBarrier() we are guaranteed that every invocation executed the barrier before any return, and all memory writes by those invocations are visible to all invocations in the subgroup.
Interestingly I tried changing if(gl_SubgroupInvocationID.x==0) to other numbers. For example if(gl_SubgroupInvocationID.x==3) yields
0:2
0:3
Finish! 2
0:0
0:1
So it seems like the subgroupBarrier() is entirely ignored.
Could the nested loop be the cause of the problem or is it something else?
Edit:
I provide here more detailed code
#version 450
#extension GL_KHR_shader_subgroup_basic : enable
#extension GL_EXT_debug_printf : enable
layout (local_size_x_id = GROUP_SIZE_CONST_ID) in; // this is a specialization constant whose value always matches the subgroupSize
shared uint copied_faces_idx;
void main() {
const uint chunk_offset = gl_WorkGroupID.x;
const uint lID = gl_LocalInvocationID.x;
// ... Some less important stuff happens here ...
const uint[2] ending = uint[2](relocated_leading_faces_ending, relocated_trailing_faces_ending);
const uint[2] beginning = uint[2](offset_to_relocated_leading_faces, offset_to_relocated_trailing_faces);
uint part = 0;
face_offset = lID;
Face face_to_relocate = faces[face_offset];
i=-1;
debugPrintfEXT("Stop 1: %d %d",gl_SubgroupID,gl_SubgroupInvocationID.x);
subgroupBarrier(); // I added this just to test see what happens
debugPrintfEXT("Stop 2: %d %d",gl_SubgroupID,gl_SubgroupInvocationID.x);
while(true){
while(face_offset >= ending[part]){
part++;
if(part>=2){
debugPrintfEXT("Stop 3: %d %d",gl_SubgroupID,gl_SubgroupInvocationID.x);
subgroupBarrier();
debugPrintfEXT("Stop 4: %d %d",gl_SubgroupID,gl_SubgroupInvocationID.x);
for(uint i=lID;i<inserted_face_count;i+=GROUP_SIZE){
uint offset = atomicAdd(copied_faces_idx,1);
face_to_relocate = faces_to_be_inserted[i];
debugPrintfEXT("Stop 5: %d %d",gl_SubgroupID,gl_SubgroupInvocationID.x);
tmp_faces_copy[offset+1] = face_to_relocate.x;
tmp_faces_copy[offset+2] = face_to_relocate.y;
}
subgroupBarrier(); // Let's make sure that copied_faces_idx has been incremented by all threads.
if(lID==0){
debugPrintfEXT("Finish! %d",copied_faces_idx);
save_copied_face_count_to_buffer(copied_faces_idx);
}
return;
}
face_offset = beginning[part] + lID;
face_to_relocate = faces[face_offset];
}
i++;
if(i==removed_face_count||shared_faces_to_be_removed[i]==face_to_relocate.x){
remove_face(face_offset, i);
debugPrintfEXT("remove_face: %d %d",gl_SubgroupID,gl_SubgroupInvocationID.x);
face_offset+=GROUP_SIZE;
face_to_relocate = faces[face_offset];
i=-1;
}
}
}
Basically what this code does is equivalent to
outer1:for(every face X in polygon beginning){
for(every face Y to be removed from polygons){
if(X==Y){
remove_face(X);
continue outer1;
}
}
}
outer2:for(every face X in polygon ending){
for(every face Y to be removed from polygons){
if(X==Y){
remove_face(X);
continue outer2;
}
}
}
for(every face Z to be inserted in the middle of polygon){
insertFace(Z);
}
save_copied_face_count_to_buffer(number_of_faces_copied_along_the_way);
The reason why my code looks so convoluted is because I wrote it in a way that is more parallelizable and tries to minimize the number of inactive threads (considering that usually threads in the same subgroup have to execute the same instruction).
I also added a bunch more of debug prints and one more barrier just to see what happens. Here are the logs that i got
Stop 1: 0 0
Stop 1: 0 1
Stop 1: 0 2
Stop 1: 0 3
Stop 2: 0 0
Stop 2: 0 1
Stop 2: 0 2
Stop 2: 0 3
Stop 3: 0 2
Stop 3: 0 3
Stop 4: 0 2
Stop 4: 0 3
Stop 5: 0 2
Stop 5: 0 3
remove_face: 0 0
Stop 3: 0 0
Stop 4: 0 0
Stop 5: 0 0
Finish! 3 // at this point value 3 is saved (which is the wrong value)
remove_face: 0 1
Stop 3: 0 1
Stop 4: 0 1
Stop 5: 0 1 // at this point atomic is incremented and becomes 4 (which is the correct value)
I found the reason why my code did not work. So it turns out that I misunderstood how exactly subgroupBarrier() decides which threads to synchronize. If a thread is inactive then it will not participate in the barrier. It doesn't matter whether the inactive thread will later become active and will eventually reach the barrier.
Those two loops are not equivalent (even though it seems like they are)
while(true){
if(end_condition){
break;
}
}
subgroupBarrier();
some_function();
and
while(true){
if(end_condition){
subgroupBarrier();
some_function();
return;
}
}
If all threads reach the end condition in the exact same iteration, then there is no problem, because all threads are active at the same time.
The issue appears when different threads might exit the loop at different iterations. If thread A passes the end condition after 2 iterations and thread B
passes end condition after 3 iterations, then there will be one entire iteration between them when A is inactive and waiting for B to finish.
In the first scenario, A will reach break first, then B will reach break second and the finally both threads will exit the loop and arrive at the barrier.
In the second scenario, A will reach the end condition first and execute the if statement, while B will be inactive, waiting for A to finish. As A reaches the barrier it will be the only active thread at that point in time and hence it will pass through the barrier without synchronizing with B. Then A will finish executing the body of if statement reach return and become inactive. Then B will actually become active again and finish executing its iteration. Then in the next iteration it will reach end condition and barrier and again ti will be the only active thread so the barrier won't have to synchronize anything.
I am trying to check if there is a space in an input line.
I have indexed the input but I got an error: "Expected ';' expected ')' "
string mike20;
int count = 0;
while (getline(cin, mike20))
for (mike20[0]); (isspace(mike20[0]); ++mike20[0])
return 0;
Firstly they are syntax error in your code, it is more like that for (mike20[0]; isspace(mike20[0]); ++mike20[0]). Secondly you seem don't understand how the for loop work. As is nothing change, so the loop is infinite.
You need a variable to browse each char of the string and do your test on each of them.
int cursor;
for (cursor = 0; cursor < number_of_char_in_mike20; ++cursor)
{
isspace(mike20[i]);
}
this code is incomplet you need to declare and initialise the number_of_char_in_mike20 variable and the isspace() function must be define if is not.
PS: don't forget braces {} for while loop and for loop, without only the first instruction is repeated.
for (initialisation(only once); test(each time); increment(each time))
first_instruction; // each time
second_instruction; // after the loop end
third_instruction; // after the loop end
fourth_instruction; // after the loop end
fifth_instruction; // after the loop end
for (initialisation(only once); test(each time); increment(each time))
{
first_instruction; // each time
second_instruction; // each time
third_instruction; // each time
}
fourth_instruction; // after the loop end
fifth_instruction; // after the loop end
I have this nested loop situation in Kotlin, imagine there are two strings "abcdef" and "bfihja". I'm comparing these two character by character using for loop. If there's a match, that character is to be removed from each string and the iteration for "S2" should start from beginning.
var S1 = "abcdef"
var S2 = "bfihja"
for(i in S1.indices) {
for(j in S2.indices){
if(S1[i]==S2[j]) {
"character removed from each"
}
What I'm having issues in is, when the character matches, the comparison for "S2" string should start from the beginning again. I can't find way restart it.
You can use a labeled outer while loop. By using continue on the outer loop, you restart your iteration. You can put break after the outer iteration so we can exit the while loop when complete.
outer#while (true) {
for (i in S1.indices) {
for (j in S2.indices) {
if (S1[i] == S2[j]) {
S1 = StringBuilder(S1).deleteCharAt(i).toString()
S2 = StringBuilder(S2).deleteCharAt(j).toString()
continue#outer
}
}
}
break
}
You should use a regular for-loop that ranges from 0 to length-of-S2 in the inner for-loop, and just reset the iterator variable to 0 when you want to "reset" the for-loop.
This question already has answers here:
Incrementor logic
(7 answers)
How do the post increment (i++) and pre increment (++i) operators work in Java?
(14 answers)
Closed 6 years ago.
Is this the proper syntax in order to set the parameters of a previously generated preparedstatement? Which occurs first, the addition of 1 to the variable i, or the usage of the variable in setting the parameter?
int i=1;
for (TagInfo tag : scannedTags){
//Pull the tag from the dbo.Tags table that matches the SiteID and TagOffSet values of the current tag in the alarm_tags list
//Set parameters for the prepared statement
dbStmtTag.setInt(i++, tag.getSiteID());
dbStmtTag.setInt(i++, tag.getTagOffset());
}
If the order of operations is that the value is incremented first, I would assume I can just add 1 AFTER setting the parameter. I'm merely asking for the sake of brevity in my code.
[To test the behaviour of i++ for myself] I'd have to write an entire test application that talks to a test database, which I would need to create.
Nonsense. All you would need to do is ...
public static void main(String[] args) {
try {
int i = 1;
System.out.printf("i is %d%n", i);
System.out.printf("i++ returned %d%n", i++);
System.out.printf("i is now %d%n", i);
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
... which produces ...
i is 1
i++ returned 1
i is now 2
I'm trying to build an LLVM pass that splits the BasicBlock and make a decision using "SplitBlockAndInsertIfThenElse" every time a binary operation is encountered, however this only allows me to split once (split at the 1st binop). could you please help me make it iterate through all the binop instructions?
Knowing that changing the position of "break;" gives me errors when running the pass. same thing happens when I put the "SplitBlockAndInsertIfThenElse" in a nested loop.
Here is my code:
for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I)
{
if (auto *op = dyn_cast<BinaryOperator>(&*I))
{
IRBuilder<> Builder(op);
Value *lhs = op->getOperand(0);
Value *rhs = op->getOperand(1);
Value *xpv = Builder.CreateAlloca(llvm::Type::getInt32Ty(llvm::getGlobalContext()), nullptr, "x");
Value *xpv2 = Builder.CreateAlloca(llvm::Type::getInt32Ty(llvm::getGlobalContext()), nullptr, "x2");
Value *add1 = Builder.CreateAdd(lhs, rhs);
Value *add2 = Builder.CreateAdd(lhs, rhs);
Value *icmp1 = Builder.CreateICmpEQ(add1, add2);
TerminatorInst *ThenTerm , *ElseTerm ;
SplitBlockAndInsertIfThenElse(icmp1, op, &ThenTerm, &ElseTerm,nullptr);
Builder.SetInsertPoint(ThenTerm);
Value *xp1 = Builder.CreateStore(add1, xpv);
Builder.SetInsertPoint(ElseTerm);
break ;
}
}
Don't perform concurrent iteration and modification of the instruction list. Iterate until you find the first instruction you care about, then break out of the loop, perform the modification, and restart the loop, starting from the next instruction after the split-before one (so the next instruction after op, in your case).