gpt4 book ai didi

C代码堆栈损坏更改变量

转载 作者:太空宇宙 更新时间:2023-11-04 00:46:45 25 4
gpt4 key购买 nike

我希望有人能帮助我。十多年来我没有用 C 代码写太多东西,两天前才把它拿回来,所以请耐心等待,因为我生疏了。谢谢!

内容:

我正在为应用程序创建一个非常简单的线程池。此代码是使用 GNU GCC 编译器在 CodeBlocks 上用 C 语言编写的。它被构建为命令行应用程序。没有链接或包含其他文件。

代码应该创建 X 个线程(在本例中我将其设置为 10),每个线程都在等待数组条目(由线程线程索引或计数标识)以获取可能需要处理的任何传入数据.一旦给定的 child 处理了通过数组传入的数据,就不需要将数据传回主线程;相反, child 应该简单地将数组条目重置为 0,以指示它已准备好处理另一个输入。主线程将接收请求并将它们分发给任何可用的线程。如果没有可用的,那么它将拒绝处理该输入。

为简单起见,下面的代码是一个完整且有效但经过修剪和删减的版本,它确实显示了我试图追踪的堆栈溢出。这编译正常,最初运行良好,但在子线程进程 (workerThread) 中的 threadIndex 值通过几次后变得损坏并跳到奇怪的值 - 通常变成我为“ sleep ”函数输入的毫秒数。

我检查过的内容:

  • threadIndex 变量不是全局变量或共享变量。
  • 所有数组都足够大,足以处理我正在创建的最大线程数。
  • 所有循环在运行前都将循环变量重置为 0。
  • 我没有用相同的名称命名多个变量。
  • 我使用 atomic_load 来确保我不会同时用两个不同的线程写入同一个全局数组变量请注意我很生疏......我可能误解了这部分的工作方式
  • 我到处都放置了测试用例以查看变量在哪里出错,但我很困惑。

最佳猜测

我的所有研究都证实了我多年前的记忆;我可能在某处越界并导致堆栈损坏。我已经在 google 和堆栈溢出上查看了许多其他类似的问题,虽然所有这些都指向我相同的结论,但我一直无法弄清楚我的代码中具体有什么问题。

#include<stdio.h>
//#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<conio.h>
//#include<unistd.h>
#define ESCAPE 27

int maxThreads = 10;
pthread_t tid[21];
int ret[21];
int threadIncoming[21];
int threadRunning[21];

struct arg_struct {
char* arg1;
int arg2;
};
//sick of the stupid upper/lowercase nonsense... boom... fixed
void* sleep(int time){Sleep(time);}


void* workerThread(void *arguments)
{
//get the stuff passed in to us
struct arg_struct *args = (struct arg_struct *)arguments;
char *address = args -> arg1;
int threadIndex = args -> arg2;
//hold how many we have processed - we are unlikely to ever hit the max so no need to round robin this number at this point
unsigned long processedCount = 0;
//this never triggers so it IS coming in correctly
if(threadIndex > 20){
printf("INIT ERROR! ThreadIndex = %d", threadIndex);
sleep(1000);
}
unsigned long x = 0;
pthread_t id = pthread_self();
//as long as we should be running
while(__atomic_load_n (&threadRunning[threadIndex], __ATOMIC_ACQUIRE)){
//if and only if we have something to do...
if(__atomic_load_n (&threadIncoming[threadIndex], __ATOMIC_ACQUIRE)){


//simulate us doing something
//for(x=0; x<(0xFFFFFFF);x++);
sleep(2001);
//the value going into sleep is CLEARLY somehow ending up in index because you can change that to any number you want
//and next thing you know the next line says "First thread processing done on (the value given to sleep)
printf("\n First thread processing done on %d\n", threadIndex);




//all done doing something so clear the incoming so we can reuse it for our next one
//this error should not EVER be able to get thrown but it is.... something is corrupting our stack and going into memory that it shouldn't
if(threadIndex > 20){ printf("ERROR! ThreadIndex = %d", threadIndex); }
else{ __atomic_store_n (&threadIncoming[threadIndex], 0, __ATOMIC_RELEASE); }
//increment the processed count
++processedCount;
}
else{Sleep(10);}
}
//no need to do atomocity I don't think for this as it is only set on the exit and not read till after everything is done
ret[threadIndex] = processedCount;
pthread_exit(&ret[threadIndex]);
return NULL;
}



int main(void)
{
int i = 0;
int err;
int *ptr[21];
int doLoop = 1;
//initialize these all to set the threads to running and the status on incoming to NOT be processing
for(i=0;i < maxThreads;i++){
threadIncoming[i] = 0;
threadRunning[i] = 1;
}
//create our threads
for(i=0;i < maxThreads;i++)
{
struct arg_struct args;
args.arg1 = "here";
args.arg2 = i;
err = pthread_create(&(tid[i]), NULL, &workerThread, (void *)&args);
if (err != 0){ printf("\ncan't create thread :[%s]", strerror(err)); }
}
//loop until we hit escape
while(doLoop){
//see if we were pressed escape
if(kbhit()){ if(getch() == ESCAPE){ doLoop = 0; } }
//just for testing - actual version would load only as needed
for(i=0;i < maxThreads;i++){
//make sure we synchronize so we don't end up pointing into a garbage address or half loading when a thread accesses us or whatever was going on
if(!__atomic_load_n (&threadIncoming[i], __ATOMIC_ACQUIRE)){
__atomic_store_n (&threadIncoming[i], 1, __ATOMIC_RELEASE);
}
}
}
//exiting...
printf("\n'Esc' pressed. Now exiting...\n");
//call to end them all...
for(i=0;i < maxThreads;i++){ __atomic_store_n (&threadRunning[i], 0, __ATOMIC_RELEASE); }
//join them all back up - if we had an actual worthwhile value here we could use it
for(i=0;i < maxThreads;i++){
pthread_join(tid[i], (void**)&(ptr[i]));
printf("\n return value from thread %d is [%d]\n", i, *ptr[i]);
}
return 0;
}

输出

这是我得到的输出。请注意,它开始变得疯狂之前需要多长时间似乎可能有所不同,但差别不大。

Output Screen with Error

最佳答案

我不相信你对 args 的处理,似乎存在竞争条件。如果您在第一个线程运行之前创建 N 个线程怎么办?然后创建的第一个线程可能会看到第 N 个线程的 args,而不是第一个,依此类推。

我不相信可以保证在非重叠区域创建循环中使用的自动变量;毕竟它们在循环的每次迭代中都超出了范围。

关于C代码堆栈损坏更改变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35204525/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com