DevC++ 多线程创建与删除与exe文件脱离DevC++运行中发现dll文件和exe文件的关系

实现了一个键盘命令控制线程创建删除,线程id显示,并在小bug解决中发现dll文件与exe文件的联系。 

命令

p :创建进程

k : 结束进程

新创建的线程运行10秒自动退出。所以在线程运行时,输入 k 可以看到命令效果

DevC++ 多线程创建与删除与exe文件脱离DevC++运行中发现dll文件和exe文件的关系_第1张图片

DevC++ 多线程创建与删除与exe文件脱离DevC++运行中发现dll文件和exe文件的关系_第2张图片

 关于一个dll文件的作用:来源于BUG的提示

有的DevC++版本在编译的时候,没有封装进线程的库,需要调用动态链接库,导致dev里内部运行,但是点击.exe文件报错。注意此时.exe文件大小是80kb

DevC++ 多线程创建与删除与exe文件脱离DevC++运行中发现dll文件和exe文件的关系_第3张图片

然后换一个DevC++编译器,重新编译,然后点击新生成的.exe文件,发现可以运行,注意此时的.exe文件大小变成185kb.

可以知道内部多了一些东西。

然后我们在把这个缺失的libwinpthread.dll文件加入同文件目录下,exe和libwinpthread.dll在同一个文件夹里,再次用之前的编译器编译,回到那个80kb的版本,然后再点击.exe文件,发现可以运行。如图。

DevC++ 多线程创建与删除与exe文件脱离DevC++运行中发现dll文件和exe文件的关系_第4张图片

行了!

注意到动态链接库libwinpthread.dll的大小是73kb,之前的不需要dll文件的exe的大小是185kb, 而80+73=153,小于185,

可以理解为另一个编译器在编译组织过程中,把一些具有dll功能的代码加进在exe文件里了。153kb距离185kb还差一些kb的内存就是用来辅助源代码和dll类似功能的代码相联系。这样离开了dll文件,exe文件也能执行。

【免费】libwinpthread-1dll多线程的动态链接库资源-CSDN文库

这是libwinpthread.dll依赖文件,如果怀疑有病毒可以不下载,目前链接里libwinpthread.dll大小是73kb,和文章截图里的大小一样。

为啥Devc++里直接点击运行按钮没提示报错呢?因为Devc++已经运行的时候启用的多线程,是直接就着Dev里面的程序继续运行,相当与dev的一部分。而直接点击exe,就脱离DevC++的多线程创建,再加上编译时没有内部加入线程代码,所以就会出现有的exe直接点击会报错,而编译器里运行却没事。

两个版本的DevC++来源:

1.封装好 EasyX 的 DevC++5.11 绿色版:百度网盘 请输入提取码(提取码:8frc)

这个版本的devc++主要是用于图形学学习,解压即用。链接来源:

另一个是VSCode风格的Devc++,是red panda Devc++。这个就是编译需要libwinpthread.dll的编译器。

最后是完整代码。

#include 
#include
#include 
#include


typedef struct node {
	int a;   	//	参数 
	int b;   // 控制停止 
} node;
//传入结构体可以实现线程和参数的动态生成

void* ptintf_hello_world(void* i) {
	while (1) {
		Sleep(1000);
		i++;
		printf("Hello world %d.\n", i);
		printf("threadId:%lu,arg:%s\n", pthread_self(), "hello\n");
	}
}
//函数带参数


void* show_old(void*i) {
	int a=((node*)i)->a;
	int cnt=0;
	while (1) {
		Sleep(2000);
		a++;
		printf("show %d.\n", a);
		printf("threadId:%lu,arg:%s\n", pthread_self(), "show\n");
		cnt++;
		if(cnt==10) {
			printf("%d  is closed\n",pthread_self());
//			线程内部退出函数 pthread_exit()
			pthread_exit(NULL);
//			retval 是void*类型的指针,可以指向任何类型的数据,它指向的数据将作为线程退出时的返回值。如果线程不需要返回任何数据,将 retval 参数置为NULL即可。
		}
//		退出之后,线程id不会复用,而是继续向后延申,相当于记录累计使用的线程数目
	}
}


//上一个版本的show_old()插入if判断
void* show(void*i) {
	int a=((node*)i)->a;
	int cnt=0;

	while (1) {
//			通过指针传入的结构体来检测 b 成员的变化 ,实现外部线程控制内部线程
		if(((node*)i)->b==-1) {
			printf("%d 线程关闭\n",pthread_self()) ;
			pthread_exit(NULL);
		} else {
			a++;
			printf("showwwwwwwwwwwwwwwwwwwwwwwwwww now is %d.\n", a);
			printf("threadId:%lu,arg:%s\n", pthread_self(), "show\n");
			cnt++;
//				10次之后自动退出
			if(cnt==10) {
				printf("%d  is closed\n",pthread_self());
//			线程内部退出函数 pthread_exit()
				pthread_exit(NULL);
//			retval 是void*类型的指针,可以指向任何类型的数据,它指向的数据将作为线程退出时的返回值。如果线程不需要返回任何数据,将 retval 参数置为NULL即可。
			}
//		退出之后,线程id不会复用,而是继续向后延申,相当于记录累计使用的线程数目
		}
		Sleep(2000);
	}
}


int main(void) {

//	int i=0;
//	pthread_t thread;
//	pthread_create(&thread, NULL, ptintf_hello_world, (void*)i);
//
//	node* bt=(node*)malloc(sizeof(node));
//	bt->a=0;
//	bt->b=0;
	需要指针,所以就把 node bt改成动态分配内存
//	pthread_t thread2;
//	pthread_create(&thread2, NULL, show_old, (void*)bt);
//
//	Sleep(2000);
//	休眠2000毫秒
//取消之前的注释,可以看到线程创建样例


	char ch[100];
	int n=1;
//	创建起始点,控制数组
	int nowstart=0;
//	关闭线程的计数器 ,控制数组
	int nowclose=0;
	//	线程池
	pthread_t have[20];
//	线程参数结构体池子
	node* check[20];

	while(1) {
		printf("请输入命令\n");
		scanf("%s",ch);
		if(strcmp("p",ch)==0) {
			node *p=(node*)malloc(sizeof(node));
			p->a=n;
			p->b=nowstart;
			check[nowstart]=p;
			n=n*10;
			nowstart++;
			pthread_create(&have[nowstart],NULL,show,(void*)p);
//			传进have[now]中的索引来使用大内存,而不是have[now]用于存储索引的小内存的
			printf("创建成功\n");
		} else if(strcmp("k",ch)==0) {
			printf("%d关闭执行中\n",nowclose);
			printf("%d\n",check[nowclose]->b);
			check[nowclose]->b=-1;
			nowclose++;
		}else if(strcmp("close",ch)==0){
			break;
		} else {
			printf("命令不存在\n");
		}
	}

	printf("exit success\n");
	return 0;
}

你可能感兴趣的:(c++,c语言)