实现了一个键盘命令控制线程创建删除,线程id显示,并在小bug解决中发现dll文件与exe文件的联系。
命令
p :创建进程
k : 结束进程
新创建的线程运行10秒自动退出。所以在线程运行时,输入 k 可以看到命令效果
关于一个dll文件的作用:来源于BUG的提示
有的DevC++版本在编译的时候,没有封装进线程的库,需要调用动态链接库,导致dev里内部运行,但是点击.exe文件报错。注意此时.exe文件大小是80kb
然后换一个DevC++编译器,重新编译,然后点击新生成的.exe文件,发现可以运行,注意此时的.exe文件大小变成185kb.
可以知道内部多了一些东西。
然后我们在把这个缺失的libwinpthread.dll文件加入同文件目录下,exe和libwinpthread.dll在同一个文件夹里,再次用之前的编译器编译,回到那个80kb的版本,然后再点击.exe文件,发现可以运行。如图。
行了!
注意到动态链接库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 <stdio.h>
#include<windows.h>
#include <pthread.h>
#include<string.h>
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;
}