1.sleep����Դ��
2.Kswapd 源码解析
3.go源码:Sleep函数与线程
4.å¦ä½è®© Qt çç¨åºä½¿ç¨ Sleep
sleep����Դ��
// 项目三—学员管理系统.cpp : 定义控制台应用程序的函函数入口点。
//
#include "stdafx.h"
#include<string.h>
#include<windows.h>
int k=0;
struct Student
{
int no;
char name[];
float score[3];
float avg;
float sum;
}stu[],数源shuchu[];
void print(int a); //输出函数
void menu(); //目录
void one(); //选择一
void two(); //选择二
void three(Student stu1[]); //选择三
void fore(); //选择四
void five(); //选择五
void six(); //选择六
void sever(); //选择七
void eight(); //选择八
void nine(); //选择九
void xuanzhe(int a); //选择函数
int chongfu(Student stu[],int a); //判断学号是否重复
int PDmingzi(Student st[],int num); //判断名字是否合法
void fanhui(); //是否返回主菜单
void fuzhi(Student a[],int num);
int _tmain(int argc, _TCHAR* argv[])
{
//登陆模板
char user[];
char passwork[];
int count=0;
while (count<3)
{
printf("\n\n\t\t请输入用户名:");
gets_s(user);
printf("\t\t请输入密码:");
gets_s(passwork);
if(strcmp(user,"admin")==0&&strcmp(passwork,"")==0)
{
system("cls");
printf("\n\n\t\t登陆成功");
Sleep();printf(">");Sleep();printf(">");Sleep();printf(">");Sleep();printf(">");
Sleep();printf(">");Sleep();printf(">");Sleep();Sleep();printf(">");Sleep();
printf(">");
menu();//调用菜单函数
break;
}
else
{
if (count==2)
{
printf("\t提示:您输入用户和密码错误次数过多,请稍后再试!源码\n");
system("cls");
break;
}
else
{
printf("\n\n\t\t登陆失败!分析请重新输入!函函数\n");
}
count++;
system("cls");
}
}
return 0;
}
//菜单
void menu()
{
system("cls");
int count=0;
while(count<3)
{
printf("\n\t\t学 员 管 理 系 统 平 台\n");
printf("---------------------------------\n");
printf("\t◎功能菜单:\n");
printf("\n\t\t-----------------------------\n");
Sleep();
printf("\t\t1、数源区块链发布平台源码单个学员的源码信息循环录入\n");
printf("\t\t------------------------------\n");
printf("\t\t2、显示所有学员的分析信息\n");
printf("\t\t------------------------------\n");
printf("\t\t3、排序显示所有学员信息\n");
printf("\t\t------------------------------\n");
printf("\t\t4、函函数插入单个学员信息\n");
printf("\t\t------------------------------\n");
printf("\t\t5、数源删除单个学员信息\n");
printf("\t\t------------------------------\n");
printf("\t\t6、源码查找单个学员信息\n");
printf("\t\t------------------------------\n");
printf("\t\t7、分析读取所有学员信息\n");
printf("\t\t------------------------------\n");
printf("\t\t8、函函数保存所有学员信息\n");
printf("\t\t------------------------------\n");
printf("\t\t9、数源退出程序\n");
printf("\t\t------------------------------\n");
printf("请选择:");
char a;
int b;
fflush(stdin);
a=getchar();
if (a>=(1+'0')&&a<=(9+'0'))
{
b=(int)a-'0';
xuanzhe(b);
}
else
{
count++;
if (count==2)
{
system("cls");
printf("错误次数过多!源码");
break;
}
}
}
}
//选择
void xuanzhe(int a)//选择
{
switch (a)
{
case 1:
system("cls");
one();
break;
case 2:
system("cls");
two();
break;
case 3:
system("cls");
three(stu);
fanhui();
break;
case 4:
system("cls");
fore();
break;
case 5:
system("cls");
five();
break;
case 6:
system("cls");
six();
fanhui();
break;
case 7:
system("cls");
sever();
break;
case 8:
system("cls");
eight();
break;
case 9:
system("cls");
nine();
break;
default:
break;
}
}
//1
void one()
{
char s;
printf("1、单个成绩循环录入:\n");
while (true)//接收输入的emule源码下载
{
while(true)
{
printf("学号:");
scanf_s("%d",&stu[k].no);
if (chongfu(stu,k))
{
printf("学号重复请重新输入!\n");
}
else
{
break;
}
}
while (true)
{
printf("姓名:");
fflush(stdin);
gets_s(stu[k].name);
int a=strlen(stu[k].name);
if (a==0)
{
printf("提示:名字不能为空,请重新输入!\n");
}
else if(PDmingzi(stu,a))
{
printf("提示:名字不能为数字,请重新输入!\n");
}
else
{
break;
}
}
for (int i = 0; i < 3; i++)
{
printf("成绩%d:",i+1);
scanf_s("%f",&stu[k].score[i]);
if (!(stu[k].score[i]<=&&stu[k].score[i]>=0))
{
i--;
printf("输入有误!!请重新输入\n");
continue;
}
}
stu[k].sum=stu[k].score[0]+stu[k].score[1]+stu[k].score[2];
stu[k].avg=stu[k].sum/3.0;
while (true)
{
printf("是否继续录入Y/N?");
fflush(stdin);
s=getchar();
if (s=='N'||s=='n')
{
fuzhi(stu,k);
print(k);
printf("是否返回主菜单(Y/N):");
char a;
fflush(stdin);
a=getchar();
if (a=='y'||a=='Y')
{
menu();
}
}
else if (s=='y'||s=='Y')
{
break;
}
else
{
printf("你的输入有误!请重新输入!\n");
}
}
k++;
}
}
//读正输入的
void print(int a)
{
printf("学号\t姓名\t成绩一\t成绩二\t成绩三\t总成绩\t平均分\n");
for (int i = 0; i <=a ; i++)
{
printf("%d\t%s\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n",shuchu[i].no,shuchu[i].name,shuchu[i].score[0],shuchu[i].score[1],shuchu[i].score[2],shuchu[i].sum,shuchu[i].avg);
}
}
void two()
{
printf("学员信息:\n");
fuzhi(stu,k);
print(k);
fanhui();
}
void three(Student stu1[])
{
//根据平均分降排序所有学员信息
for (int i = 0; i <k ; i++)
{
for (int j = 0; j < k-i; j++)
{
if (stu1[j].avg<stu[j+1].avg)
{
Student temp;
temp=stu1[j];
stu1[j]=stu1[j+1];
stu1[j+1]=temp;
}
}
}
fuzhi(stu1,k);
print(k);
}
void fore()
{
three(stu);
printf("1、插入单个学生信息:\n");
while (true)//接收输入的
{
if (k>0)
k++;
while(true)
{
printf("学号:");
scanf_s("%d",&stu[k].no);
if (chongfu(stu,k))
{
printf("学号重复请重新输入!\n");
}
else
{
break;
}
}
while (true)
{
printf("姓名:");
fflush(stdin);
gets_s(stu[k].name);
int a=strlen(stu[k].name);
if (a==0)
{
printf("提示:名字不能为空,请重新输入!\n");
}
else if(PDmingzi(stu,a))
{
printf("提示:名字不能为数字,请重新输入!\n");
}
else
{
break;
}
}
for (int i = 0; i < 3; i++)
{
printf("成绩%d:",i+1);
scanf_s("%f",&stu[k].score[i]);
if (!(stu[k].score[i]<=&&stu[k].score[i]>=0))
{
i--;
printf("输入有误!!图时尚源码请重新输入\n");
continue;
}
}
stu[k].sum=stu[k].score[0]+stu[k].score[1]+stu[k].score[2];
stu[k].avg=stu[k].sum/3.0;
char s;
while (true)
{
printf("是否继续插入Y/N?");
fflush(stdin);
s=getchar();
if (s=='N'||s=='n')
{
system("cls");
fanhui();
}
else if (s=='y'||s=='Y')
{
break;
}
else
{
printf("你的输入有误!请重新输入!\n");
}
}
}
}
void five()
{
//删除单个学员的信息
print(k);
printf("请输入要删除的学员信息的学号:");
int num;
scanf_s("%d",&num);
int i;
for ( i= 0; i <= k; i++)
{
if (stu[i].no==num)
{
break;
}
}
for (int j = i; j <= k; j++)
{
stu[i]=stu[i+1];
}
k-=1;
fanhui();
}
void six()
{
Student a[1];
while (true)
{
printf("请输入要查找的学员信息的学号:");
int num;
scanf_s("%d",&num);
int i;
for ( i= 0; i <= k; i++)
{
if (stu[i].no==num)
{
a[0]=stu[i];
fuzhi(a,0);
print(0);
}
}
}
}
void sever()
{
FILE *p;
fopen_s(&p,"d:\\项目三存储.txt","rb");
if (p!=NULL)
{
int n=fread(stu,sizeof(struct Student),,p);
if (k==0)
{
k=n-1;
}
}
fclose(p);
}
void eight()
{
FILE *fp;
fopen_s(&fp,"d:\\项目三存储.txt","wb");
fwrite(&stu,sizeof(struct Student),k+1,fp);
fflush(fp);
fclose(fp);
printf("保存成功!\n");
fanhui();
}
void nine()
{
exit(1);
}
int chongfu(Student stu[],int a)
{
for (int i = 0; i < a; i++)
{
if (stu[a].no==stu[i].no)
{
return 1;
}
}
return 0;
}
int PDmingzi(Student st[],int num)
{
for (int i = 0; i <= num; i++)
{
if(st[k].name[i]>='0'&&st[k].name[i]<='9')
{
return 1;
}
}
return 0;
}
void fuzhi(Student a[],int num)
{
for (int i = 0; i <= num; i++)
{
shuchu[i]=a[i];
}
}
void fanhui()
{
printf("是否返回主菜单(Y/N):");
char a;
fflush(stdin);
a=getchar();
if (a=='y'||a=='Y')
{
menu();
}
}
Kswapd 源码解析
kswapd是Linux内核中的一个内存回收线程,主要用于内存不足时回收内存。初始化函数为kswapd_init,内核为每个节点分配一个kswapd进程。每个节点的pg_data_t结构体中维护四个成员变量,用于管理kswapd线程。
在初始化后,每个节点的kswapd线程进入睡眠状态。唤醒时机主要在被动唤醒和主动唤醒两种场景:被动唤醒是内存分配进程唤醒并完成异步内存回收后,对节点内存环境进行平衡度检查,若平衡则线程短暂休眠ms后主动唤醒。主动唤醒是内存回收策略调用kswapd,对节点进行异步内存回收,vc辅助源码让节点达到平衡状态。
内存回收包括快速和直接两种方式,但系统周期性调用kswapd线程平衡不满足要求的节点,因为有些任务内存分配不允许阻塞或激活I/O访问,回收内存相当于亡羊补牢,系统利用空闲时间进行内存回收是必要的。
kswapd线程通过module_init(kswapd_init)创建,一般处于睡眠状态等待被唤醒,当系统内存紧张时,会唤醒kswapd线程,调整不平衡节点至平衡状态。
kswapd函数包含alloc_order、reclaim_order和classzone_idx三个变量,用于控制线程执行流程。kswapd_try_to_sleep函数判断是否睡眠并让出CPU控制权,同时是cf飞刀源码线程唤醒的入口。balance_pgdat函数是实际内存回收操作,涉及内存分配失败后唤醒kswapd线程,调用此函数对指定节点进行异步内存回收。
kswapd_shrink_node函数通过shrink_node对低于sc->reclaim_idx的非平衡zone区域进行回收。
总结kswapd执行流程,其生命周期与Linux操作系统相似,平时处于睡眠状态让出CPU控制权。在内存紧张时被唤醒,有被动唤醒和周期性主动唤醒两种时机。被动唤醒发生在内存分配任务获取不到内存时,表明系统内存环境紧张,主动唤醒则是内存回收策略的执行。线程周期性唤醒在被动唤醒后的短暂时间内,原因在于系统内存环境紧张,需要在这段时间内进行内存回收。
go源码:Sleep函数与线程
在探索 Go 语言的并发编程中,Sleep 函数与线程的交互方式与 Java 或其他基于线程池的并发模型有所不同。本文将深入分析 Go 语言中 Sleep 函数的实现及其与线程的互动方式,以解答关于 Go 语言中 Sleep 函数与线程关系的问题。
首先,重要的一点是,当一个 goroutine(g)调用 Sleep 函数时,它并不会导致当前线程被挂起。相反,Go 通过特殊的机制来处理这种情景,确保 Sleep 函数的调用不会影响到线程的执行。这一特性是 Go 语言并发模型中独特而关键的部分。
具体来说,当一个 goroutine 调用 Sleep 函数时,它首先将自身信息保存到线程的关键结构体(p)中并挂起。这一过程涉及多个函数调用,包括 `time.Sleep`、`runtime.timeSleep`、`runtime.gopark`、`runtime.mcall`、`runtime.park_m`、`runtime.resetForSleep` 等。最终,该 goroutine 会被放入一个 timer 结构体中,并将其放入到 p 关联的一个最小堆中,从而实现了对当前 goroutine 的保存,同时为调度器提供了切换到其他 goroutine 或 timer 的机会。因此,这里的 timer 实际上代表了被 Sleep 挂起的 goroutine,它在睡眠到期后能够及时得到执行。
接下来,我们深入分析 goroutine 的调度过程。当线程 p 需要执行时,它会通过 `runtime.park_m` 函数调用 `schedule` 函数来进行 goroutine 或 timer 的切换。在此过程中,`runtime.findrunnable` 函数会检查线程堆中是否存在已到期的 timer,如果存在,则切换到该 timer 进行执行。如果 timer 堆中没有已到期的 timer,线程会继续检查本地和全局的 goroutine 队列中是否还有待执行的 goroutine,如果队列为空,则线程会尝试“偷取”其他 goroutine 的任务。这一过程包括了检查 timer 堆、偷取其他 p 中的到期 timer 或者普通 goroutine,确保任务能够及时执行。
在“偷取”任务的过程中,线程会优先处理即将到期的 timer,确保这些 timer 的准时执行。如果当前线程正在执行其他任务(如 epoll 网络),则在执行过程中会定期检查 timer 到期情况。如果发现其他线程的 timer 到期时间早于自身,会首先唤醒该线程以处理其 timer,确保不会错过任何到期的 timer。
为了证明当前线程设置的 timer 能够准时执行,本文提出了两种证明方法。第一种方法基于代码细节,重点分析了线程状态的变化和 timer 的执行流程。具体而言,文章中提到的三种线程状态(正常运行、epoll 网络、睡眠)以及相应的 timer 执行情况,表明在 Go 语言中,timer 的执行策略能够确保其准时执行。第二种方法则从全局调度策略的角度出发,强调了 Go 语言中线程策略的设计原则,即至少有一个线程处于“spinning”状态或者所有线程都在执行任务,这保证了 timer 的准时执行。
总之,Go 语言中 Sleep 函数与线程之间的交互方式,通过特殊的线程管理机制,确保了 goroutine 的 Sleep 操作不会阻塞线程,同时保证了 timer 的准时执行。这一机制是 Go 语言并发模型的独特之处,为开发者提供了一种高效且灵活的并发处理方式。
å¦ä½è®© Qt çç¨åºä½¿ç¨ Sleep
Qt 为ä½æ²¡ææä¾ Sleep
论åä¸ä¸æ¶è§å°æ人é®ï¼
Qt 为ä»ä¹æ²¡ææä¾è·¨å¹³å°ç sleep å½æ°ï¼
使ç¨å¹³å°ç¸å ³ç Sleep æ nanosleep 以åï¼çé¢ä¸ºä»ä¹æ²¡æååºï¼
QThread ä¸æä¾äºprotected æéç sleep å½æ°ï¼å¦ä½ç¨å°ä¸»çº¿ç¨ä¸ï¼
ä½¿ç¨ QTest ä¸ç qSleepï¼å¨windowsä¸å¦ä½éèæ§å¶å°ï¼
è¿äºé®é¢å ¶å®å½ç»ä¸ºä¸ç¹ï¼å¨ä¸»çº¿ç¨ä¸ä½¿ç¨è¿äºå½æ°æ¯ä¸ç§é误ï¼è¿ä¼ç´æ¥å¯¼è´çé¢æ æ³å·æ°ï¼ç¨æ·ä¸ç¨åºæ æ³äº¤äºã
Qtä¸æä¾ï¼æ¯å ä¸ºä½ ä¸éè¦å¨ä¸»çº¿ç¨ä¸ä½¿ç¨ sleep å½æ°ã
å¦ä½è®©ç¨åºçå¾ ä¸æ®µæ¶é´
QTime
QTime t;
t.start();
while(t.elapsed()<);
è¿ç§æ»å¾ªç¯ä¹æ¯ä¸ç§å¸¸è§é误ç¨æ³ãä½æ¹ææ£ç¡®çè¿æ¯æ¯è¾ç®åçï¼
QTime t;
t.start();
while(t.elapsed()<)
QCoreApplication::processEvents();
ä¸åå°å¤çäºä»¶ï¼ä»¥ä½¿å¾ç¨åºä¿æååºã
QElapsedTimer
è¿æ¯Qt4.7å¼å ¥çæ°çç±»ï¼åQTimeç¸æ¯ï¼å®æä¾äºæ´å¿«çè®¡ç® elapsed æ¶é´çæ¹æ³ã
QElapsedTimer t;
t.start();
while(t.elapsed()<)
QCoreApplication::processEvents();
QTest::qWait
è¿æ¯QTest模åæä¾ççå¾ å½æ°
ä¸é¢æ¯å ¶æºä»£ç ï¼åæ们åé¢ç代ç å¾åå§ï¼ï¼ï¼
namespace QTest
{
inline static void qWait(int ms)
{
Q_ASSERT(QCoreApplication::instance());
QElapsedTimer timer;
timer.start();
do {
QCoreApplication::processEvents(QEventLoop::AllEvents, ms);
QTest::qSleep();
} while (timer.elapsed() < ms);
}
...
å ¶å®æ²¡ä»ä¹éå,对å§ï¼ä½æ¯å 为å®QTest模åï¼æ以å¨ç¨åºä¸æ们ä¸è¦ä½¿ç¨å®ã
QEventLoop
é åQTimer使ç¨å±é¨ç eventLoop ä¹æ¯ä¸ä¸ªä¸éçéæ©ãä¾åï¼
QEventLoop eventloop;
QTimer::singleShot(, &eventloop, SLOT(quit()));
eventloop.exec();
QTimer å QBasicTimer
è¿ä¸¤ä¸ªåæ¬æ没æä»ä¹ç´æ¥å ³ç³»ï¼QTimer估计大家é½å¾çäºãèQBasicTimer估计å¾å°æ人ç¨ã
ä¸QTimerç¸æ¯ï¼QBasicTimeræ´å¿«éãè½»éãåºå±ã
ä¸QTimerç¸æ¯ï¼å®ä¸æ¯QObjectçæ´¾çç±»ã
跨平å°çsleep
尽管ä¸å¼å§æ们就说äºï¼ä¸éè¦è¿ä¸ªä¸è¥¿ãä½ä¸æé¤æç§åºåä¸ï¼ä½ ç¡®å®éè¦è¿ä¸ªä¸è¥¿ãå¦ä½å®ç°ä¸ä¸ªè·¨å¹³å°ç sleep å¢ï¼
æ们ä¸å¼å§ä¹æå°äºï¼QThreadç±» å QTest模åé½æä¾äºsleepå½æ°ï¼å ¶å®æ们åªéè¦ççä»ä»¬çæºç å°±å¤äºï¼
QTest 模åä¸çå½æ°å¾ç®åï¼windowsä¸è°ç¨Sleepï¼å ¶ä»å¹³å°è°ç¨ nanosleepï¼ï¼
void QTest::qSleep(int ms)
{
QTEST_ASSERT(ms > 0);
#ifdef Q_OS_WIN
Sleep(uint(ms));
#else
struct timespec ts = { ms / , (ms % ) * * };
nanosleep(&ts, NULL);
#endif
}
çQThreadçæºç ï¼windowsä¸åæ ·ç´æ¥è°ç¨Sleepï¼ä½éwindowsçå®ç°æ¯è¿ä¸ªå°±å¤æå¤äºï¼
[cpp] view plain copy
/* /internal
helper function to do thread sleeps, since usleep()/nanosleep()
aren't reliable enough (in terms of behavior and availability)
*/
static void thread_sleep(struct timespec *ti)
{
pthread_mutex_t mtx;
pthread_cond_t cnd;
pthread_mutex_init(&mtx, 0);
pthread_cond_init(&cnd, 0);
pthread_mutex_lock(&mtx);
(void) pthread_cond_timedwait(&cnd, &mtx, ti);
pthread_mutex_unlock(&mtx);
pthread_cond_destroy(&cnd);
pthread_mutex_destroy(&mtx);
}
void QThread::sleep(unsigned long secs)
{
struct timeval tv;
gettimeofday(&tv, 0);
struct timespec ti;
ti.tv_sec = tv.tv_sec + secs;
ti.tv_nsec = (tv.tv_usec * );
thread_sleep(&ti);
}