-
2021-07-07 16:21:33
对于固定次数的情况下的循环 for 循环更加的好用
而对于不固定次数,或者次数不明的情况则使用 while 循环更加的方便。
更多相关内容 -
为什么python中while不能使用全局变量呢??
2019-09-04 17:47:57python打印三位数水仙花数的时候。 i=100 while i a=i//100 b=(i-a*100)//10 ... 为什么a,b,c三个式子要放在while里面而不是while外面呢?? 本人尝试过放在外面,但是无法输出。 -
为什么虚假唤醒可以通过 while避免 ,if却不能呢?
2020-11-20 18:20:51虚假唤醒 Spurious wakeiups 指 :在线程的 等待/唤醒 的过程中,等待的线程被唤醒后,在条件不满足的情况依然继续向下运行了。 Java官方给的Api 的代码块如下 synchronized (obj) { while (<condition does not ...虚假唤醒<spurious wakeups>
-----写在前面: 最近学习java因为这个问题困扰了好几天,结果发现是因为一个特别明显的原因。因此写下这篇文章提醒自己! 与君共勉!
虚假唤醒 Spurious wakeiups 指 :在线程的 等待/唤醒 的过程中,等待的线程被唤醒后,在条件不满足的情况依然继续向下运行了。
Java官方给的Api 的代码块如下
synchronized (obj) { while (<condition does not hold> and <timeout not exceeded>) { //.....省略....... obj.wait(timeoutMillis, nanos); } }
那么,为什么官方推荐使用 while 关键字 而不是 if 关键字呢?
while or if ?
我们先看以下代码
public class WhyWhile { //判断线程是否运行的条件, static int control; //锁对象; static final Object lock = new Object(); //主线程; public static void main(String[] args) { Scanner sc = new Scanner(System.in); //只有control == 1才打印的线程; new Thread(() -> { while (true) { synchronized (lock) { **while** (control != 1) { System.out.println("A wait 前"); try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("A wait 后"); } System.out.println("== 1"); lock.notifyAll(); } } },"Thread-1").start(); //只有control == 2才打印的线程; new Thread(() -> { **while** (true) { synchronized (lock) { while (control != 2) { System.out.println("B wait 前"); try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("B wait 后"); } System.out.println("== 2"); lock.notifyAll(); } } },"Thread-2").start(); while (true) { control = sc.nextInt(); //输入后,通知所有需要lock的线程 synchronized (lock) { lock.notifyAll(); } } } }
以上代码包含了 三个线程 :main,Thread-1(下文用 线程1 代替),Thread-2(下文用 线程2 代替)。以上代码简要如下
control == 1 线程1 打印 “ == 1” control == 2 线程1 打印 “ == 2” control != 1 and control != 2 线程 1 和 线程 2 进入到等待状态 – main 线程是用来 设置 数字control,之后通知所有线程 运行以上代码;
输入1后,我们可以看到如下结果;
这说明:当前 线程1 和 线程2 都进入到了等待状态;尝试输入一个1
可以看到 输入1以后,线程1 被唤醒,从lock.wait()下一行开始运行,也就是从等待后的位置开始运行;继续往下看结果,可以看到如下
可以看到,线程2在次过程中也被 lock.notifyAll()唤醒过 (这里指 线程1 的代码块中的notifyAll)如过我们把 线程2 中的 while 换成 if 呢?
//只有control == 2才打印的线程; new Thread(() -> { while (true) { synchronized (lock) { //只把 while 修改成了 if if (control != 2) { System.out.println("B wait 前"); try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("B wait 后"); } System.out.println("== 2"); lock.notifyAll(); } } }).start();
接下来我们再运行一次,同样输入 1;
可以看见,有时候 线程2 也会被唤醒后输出结果; 这明显出现了 错误结果;
错误结果分析
在进行错误结果分析前需要记住通过以上代码得到的两个结论:
- 线程被唤醒后,会从 wait() 处开始继续往下执行;
- while 被掉换成 if 后出现了虚假唤醒,出现了我们不想要的结果;
While 和 if 特点
if(condition){ 代码块..... } 输出语句....
如上,if 判断condition为 true后,会
先执行代码块,再执行输出语句
先执行代码块,再执行输出语句
先执行代码块,再执行输出语句。通过这一条,我们分析 线程2 的while被替换成if后,以及替换前的代码的运行顺序;
首先是 if
if (control != 2) { System.out.println("B wait 前"); try { //1.在这等待 lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } //2.被唤醒后输出"B wait 后"; System.out.println("B wait 后"); } //3.跳出if输出"== 2"; System.out.println("== 2"); //4.通知其他需要锁的对象; lock.notifyAll();
然后 while 呢?
//3.回到while条件继续判断 while (control != 2) { System.out.println("B wait 前"); try { //1.在这等待 lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } //2.被唤醒后输出"B wait 后"; System.out.println("B wait 后"); } //运行不到, System.out.println("== 2"); lock.notifyAll();
if 和 while 不同的判断逻辑让使用 while 可以避免虚假唤醒,因为唤醒后继续向下运行,还是需要再次判断条件。而 if 就 直接运行下去了,如果要使用 if 避免虚假唤醒,需要与else搭配使用(如下),或者直接把正确的输出语句放入if代码块中;
if (control != 2) { System.out.println("B wait 前"); try { //1.在这等待 lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } //2.被唤醒后输出"B wait 后"; System.out.println("B wait 后"); }else{ System.out.println("== 2"); lock.notifyAll(); }
总结
- 线程如果进入等待状态,被唤醒后从wait()开始向下继续执行代码;
- 如果要用 if 判断线程的运行条件,最好与else相结合;
-
这个while循环终止了却跳不出来为什么
2021-05-20 10:37:56#includemain(){chara;scanf_s("%c",&a);while(a!...}运行结果是循环能停止,但是跳不出来,不知道为什么。解决方案10不要使用while(条件)更不要使用while(组合条件)要使用while(1){if(条件1)br...#include
main(){
char a;
scanf_s("%c", &a);
while (a!= "@")
{
scanf_s("%c", &a);
printf("kek ");
}
printf("oo ");
}
运行结果是循环能停止,但是跳不出来,不知道为什么。
解决方案
10
不要使用
while (条件)
更不要使用
while (组合条件)
要使用
while (1) {
if (条件1) break;
//...
if (条件2) continue;
//...
if (条件3) return;
//...
}
原因是前两种写法在语言表达意思的层面上有二义性,只有第三种才忠实反映了程序流的实际情况。
典型如:
下面两段的语义都是当文件未结束时读字符
while (!feof(f)) {
a=fgetc(f);
//...
b=fgetc(f);//可能此时已经feof了!
//...
}
而这样写就没有问题:
while (1) {
a=fgetc(f);
if (feof(f)) break;
//...
b=fgetc(f);
if (feof(f)) break;
//...
}
相似的例子还可以举很多。
10
printf里面的%和变量的一一对应关系
scanf里面的%和变量以及变量前加不加&的一一对应关系
是C代码中非常容易出错的地方,而且通常编译还不出错。
所以在编译源代码之前值得专门仔细检查一遍甚至多遍。
在每个最后不带\n的printf后面加fflush(stdout);
在每个不想受接收缓冲区旧内容影响的scanf前面加rewind(stdin);
另外请检查scanf的返回值。
//请今后要用
char c;
scanf("%c",&c);
//时,都改为
char s[2];
char c;
scanf("%1s",s);
c=s[0];
10
scanf_s要指定每个对应“c”、“s”以及传说中的“[”格式的缓冲区的大小。
char c;
scanf_s("%c", &c, 1); // 思考题:为什么不用sizeof?
引用:
Quote: 引用:
//请今后要用
char c;
scanf("%c",&c);
//时,都改为
char s[2];
char c;
scanf("%1s",s);
c=s[0];
诶,这段代码没看懂,为什么啊?
本意是为了“吃”掉换行,和在之后加fflush(stdin)的做法相似(但fflush“吃”得更多)。
然而这“都”字散发着浓郁的经验主义(教条主义)的气息。
10
引用:
是原因是sizeof返回的是字节大小,所以不行?(一本正经的胡说八道)本人也不知道
这个系列要的“缓冲区大小”指的是“能容纳的字符个数”而不是“字节个数”。
窄字符版本要的是char的个数,宽字符版本要的是wchar_t的个数。
所以对于数组缓冲区(buf),直接sizeof(buf)是错误的;sizeof(buf)/sizeof(buf[0])、_countof(buf)之类才是正确的。
而对于单个字符的缓冲区,1个char c的大小就是1,1个wchar_t c的大小也是1;sizeof(c)一则多余,二则对于后者是错误的。
CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明这个while循环终止了却跳不出来为什么!
-
c++中while(cin)不能执行的问题
2019-03-20 22:21:12前几天在用链表实现大整数求和的时候,因为要输入两个大整数,我接连使用了两个while(cin),但是运行的时候,却只能输入第一个整数,当第一个整数输入并回车后程序就直接就运行完毕,并没有输入第二个数的机会。...前几天在用链表实现大整数求和的时候,因为要输入两个大整数,我接连使用了两个while(cin),但是运行的时候,却只能输入第一个整数,当第一个整数输入并回车后程序就直接就运行完毕,并没有输入第二个数的机会。
结果如下:
当时的代码:
# include <iostream> # include <vector> using namespace std; struct ADD { int number; struct ADD *next; }; int main() { vector<int> result; struct ADD *head_a = new ADD, *head_b = new ADD, *p, *p1, *p2, *q, *q1, *s, *temp; int count_a = 0, count_b = 0; s = p = head_a; q = head_b; //头插法保存头结点 head_a->next = NULL; head_b->next = NULL; p1 = new ADD; cout << "请输入第一个加数(每位数之间加一个空格且输入n结束):" << endl; while (cin >> p1->number) { //*********************第一个while(cin) count_a++; p1->next = head_a->next; head_a->next = p1; p1 = new ADD; } cout << "请输入第二个加数(每位数之间加一个空格且输入n结束):" << endl; q1 = new ADD; while (cin >> q1->number) { //***********************第二个while(cin) count_b++; q1->next = head_b->next; head_b->next = q1; q1 = new ADD; } if (count_b > count_a) { temp = p; p = q; q = temp; } s = p = p->next; q = q->next; while (q) { if ((q->number + p->number) < 10) { p->number = q->number + p->number; } else { p->number = (p->number + q->number) % 10; if (p->next) { //检测是否p->next还有值,如果位数相等则访问会有冲突 (p->next)->number++; } if (!p->next) { //p->next为空即证明位数相等,因为已经确定p>=q的长度,加一个一 p2 = new ADD; p2->number = 1; p->next = p2; p = p2; p->next = NULL; } } p = p->next; q = q->next; } while (s) { result.push_back(s->number); s = s->next; } for (auto c = result.rbegin(); c != result.rend(); c++) { cout << *c; } system("pause"); return 0; }
后来想到以前在使用stringstream流时每使用一次都要用到.clear()来清空流中的数据,但是加了之后还是不起作用,当时感觉那叫一个崩溃,后来请教学长才知道,原来还需要一个.ignore()
cin.clear(); //清除错误状态 cin.ignore();//跳过无效数据
在两个while(cin)加入上边两行就正确了:
仔细想了想,问题就处在cin输入流对象上。cin是一个输入流对象,当进行第一个while循环时我输入了一个字母来结束循环,而最后输入字母完全是为了结束输入数字,这个字母没有任何的意义,所以加上cin.ignore()来路过无效数据,而此时第二个while(cin)因为使用同一个cin对象,所以也被判断为假,造成第二个循环不能执行,因此,要加上cin.clear()来清除错误状态,才能使第二个while(cin)能够正常执行。
这个以前真的时没注意过,发上来分享一下。
-
java多线程wait时为什么要用while而不是if
2018-11-06 17:44:52从上面的截图,我们可以看出,在使用wait方法时,需要使用while循环来判断条件十分满足,而不是if,那么我们思考以下,如果使用if会怎么样? 为方便讲解,我们来看一个被广泛使用的生产消费的例子。代码部分参考 ... -
BUG: scheduling while atomic 分析 and 为什么中断不能睡眠
2019-07-17 17:14:28遇到一个BUG: scheduling while atomic: kworker/0:2/370/0x00000002;看了这篇文章BUG: scheduling while atomic 分析...先看下为什么会打印出这句: schedule() -> __schedule() -> schedule_debug() s... -
Java基础——不能确定循环次数时用while
2020-10-05 17:17:26知识点:for循环,while循环 思路:在第一层循环中依次遍历数组,遇到0时,后位依次往前挪一个位置;因为数组中0的数量是未知的,如果遇到连续的两个0,则第二个零依然在数组里,所以这里用到while,同时加个计数器... -
while循环到底能不能模拟for?两极反转你永远也猜不到
2020-03-13 15:29:44大家用的最多的循环语句肯定是for,那能不能用while模拟一下for完成一些循环? 如题,用while去模拟for,打印数组的全部元素 let arr = [1, 2, 3]; for(let i = 0; i < arr.length; i++) { consoel.log(arr[i]);... -
C语言while循环语句 do while语句 for循环语句
2021-05-21 00:52:23} 2.for语句的注意事项 (1)各表达式之间分号不能省略 (2)表达式1与表达式2与表达式3均可省略,一般是不省略的。 ①当表达式1省略时,相当于省去了为循环变量赋初值,此时应在for语句之前给循环变量赋初值 ②当... -
vs code显示error while fetching extensions.xhr failed,不能使用扩展资源怎么办
2022-04-29 17:47:49作为一个新手,才下载好vs code,设置中文的时候显示error while fetching extensions.xhr failed,不能使用扩展(图是后来截的图,报的错不一样) 我也是找了很久才找到方法,原因很简单,打开此电脑,在c盘中... -
while循环使用方法
2021-06-22 19:37:43while循环使用方法2019-11-01 08:53:38文/陶凯月while是计算机的一种基本循环模式。可是有什么用法呢?下面就和小编一起了解一下吧,希望对大家有所帮助。while循环的用法while循环开始后,先判断条件是否满足,如果... -
while与dowhile循环的用法
2021-10-23 10:34:17while循环的基本用法: 基本格式: while (表达式) 语句A; 使用范围: while也是只能控制一个语句,若要控制多个语句则需要加{}花括号。 注意: while 与for循环是可以相互转化的。 如: for(1; 2... -
详解python基础之while循环及if判断
2021-02-03 10:11:32wlile循环while True表示永远为真,不管是什么条件都会向下执行,下面是写的一个例子。 #!/usr/bin/env pythonage = 24 #给age赋一个值while True: #进入循环inputting = int (input("The input number i... -
MFC中做了一个while循环,现在发现当while执行的时候,其他的按钮都不能动
2014-06-16 07:31:41MFC中做了一个while循环,利用一个标识变量(flag=1)。现在发现当while执行的时候,其他的按钮都不能动。所以也没有办法改变标识,即使按了stop的按钮,修改标识(flag=0)也没有办法退出while循环。 -
while语句可以用break吗_使用break跳出整个循环
2020-11-21 04:26:55break语句用于终止循环,可以用在while循环和for循环中,当循环条件不为False或者序列还没有完全被迭代完毕时,使用break语句也可以使循环停止执行。在for循环使用break在下面这个例子中,正常运行结果应该输出1到10... -
python中的while循环和for循环的使用
2021-02-02 22:55:19while语句包含几部分组成关键字条件(求值为true或flase的表达式:换句话说就是判断语句)以冒号结尾从新行开始时,缩进的代码块,被称为(while的子句)用代码举个例子:a=0while a<9:print("输出了”)a+=1最后输出... -
while(cin>>word)在什么时候结束此循环的问题
2018-09-27 19:57:55word)这种循环时,编译运行往往会出现循环不能终止的状况,所以我们有了不知道如何结束这种循环的疑惑。 在 Unix 系统中的实际的现象为: * 当输入为“字符串,回车,Ctrl+D”的时候,跳出循环; * 当输入... -
java多线程下为什么建议使用while不使用if
2018-05-03 19:22:21当有多个消费者的时候,还使用if判断是否await就会产生问题,这是因为一个生产者消费者模型的任务队列,一个消费者一次放入多个任务,然后用notifyAll通知消费者,但是并非所有被唤醒的消费者都能取到一个任务,那么... -
python中while循环的基本使用
2020-12-09 10:30:24一、while循环while 条件: 如果条件为True,会一直循环代码块(循环体)else:当上面的条件为假。才会执行执行顺序:判断条件是否为真。如果真,执行循环体。然后再次判断条件....知道循环条件为假,程序退出。死循环:... -
JavaScript中while以及do while语句的使用
2020-12-02 18:00:04while语法 while (条件) { 要执行的代码块 ...不能忘记i++ 语句,否则会变成死循环。 dowhile语法 do { 要执行的代码块 } while (条件); 例子: var i=0; do{ console.log(i) i++; } ... -
while(true)何时跳出循环?
2021-02-13 01:00:33while(true)是不会跳出循环的。在while中括号里为一个条件值,只要当条件为真的时分,会执行这条语句,直到条件为false的时分,则会跳出该循环语句。而在这里括号里的值为true,也就意味着会不断执行该条语句。除了... -
多线程情况下建议使用while而不是if
2018-08-22 21:00:38在多线程的编程实践中,wait()的使用方法如下: synchronized (monitor) { //判断条件是否得到满足 while(!locked) { //等待唤醒 ...那为什么非要while判断,而不采用if判断呢? synchronize... -
多线程操作中为什么使用while而不是if来做判断状态是否就绪
2018-05-24 23:34:00假设有三个线程ABC,A为生产者线程,B为消费者线程,C为破坏者线程。三个线程都进入一个共享对象的方法(当然不是...如果是while就不一样了,就会继续检查条件。1.容器类EventStoage.javapackage sss; import java.... -
if 和 while 的使用区别
2020-11-22 15:15:09欢迎使用Markdown编辑器 项目场景: 提示:这里简述项目相关背景: 例如:项目场景:示例:通过蓝牙芯片(HC-05)与手机 APP 通信,每隔 5s 传输一批传感器数据(不是很大) 问题描述: 提示:这里描述项目中遇到的问题... -
while的用法_C语言中while的用法
2021-05-19 05:44:46c语言中while的用法当n==1时执行while循环结构里的语句,当n不等于1时,则跳过该循环执行循环体外的语句。while 循环的格式:while (表达式){语句;}while 循环的执行顺序:当表达式为真,则执行下面的语句,语句... -
完全真正理解wait和notify使用的时候wait一定要放在while循环里面!
2020-05-03 11:12:38说实话,第一遍看这个概念并没有看懂,第二遍硬磕了一下,发现原来...while(){…}如果说满足了条件,那么就会进入大括号里面,在里面呆了一段时间,要想出来那得先去while判断一下,如果满足,还是不能出来。 即if... -
c#入门之循环语句使用详解(for循环、do/while)
2021-01-20 06:24:56而这些方面的差异,又是比较细微的,所以往往在学的时候依靠经验能很快理解,但过后却发现并未能使(掌)用(握)。 do / while循环的意义,其实就是重复执行语句,当然,还会有相应的条件判断,不然就成死循环了。... -
为什么在for循环中不需要先定义变量 而是直接变量in range(),但是在在while循环中需要先定义变量?
2019-12-12 11:11:01首先你要确定for和while里面的各个字段分别表示什么含义: Python 中的循环语句有 2 种,分别是 while 循环和 for 循环 for 循环语句的执行流程如图 1 所示。 for 循环语句的执行流程图 图 1 for 循环语句的执行... -
while(1) 什么意思 while(i--)什么意思? 在C++语言中,i++与++i有什么区别?那i--和--i呢
2021-05-21 04:48:25while(1) 什么意思 while(i--)什么意思? 在C++语言中,i++与++i有什么区别?那i--和--i呢while(1) 什么意思 while(i--)什么意思? 在C++语言中,i++与++i有什么区别?那i--和--i呢相关问题:匿名网友:while语句的...