- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在开始使用 C 中的 pthreads,我也是一个疯狂的人,我尽可能地把我的代码写成“无错误”。
尽管试图格外小心,但 valgrind 告诉我,无论天气如何,我都在泄漏内存:
我知道这已经被讨论过(参见 this 、 this 和 this ),但我仍然很好奇:
正如我从之前的答案和 valgrind 跟踪中了解到的那样,pthread_create() 是根本原因,根据需要扩展线程使用的堆栈并有时重用它,因此缺少一些释放。但不太清楚的是为什么它取决于执行运行以及为什么它也会在创建分离线程时发生。正如我从某些答案、评论以及该人那里看到的那样,线程完成后将释放分离线程的资源。我已经尝试了各种调整来解决这个问题(在每个线程结束之前添加一个 sleep 时间,在主线程结束之前,增加堆栈大小,添加更多“工作”......)但它并没有改变最终结果差了很多。另外,为什么在处理分离线程时整体“mallocs()”的数量是随机的,valgrind 是否会丢失一些分离线程?这似乎也不取决于堆栈大小。
所提供的代码是一个经理/ worker 模型的模拟示例,恕我直言,线程管理的 joinable/join() 方法似乎更适合。
感谢您提供的任何启发!我也希望这些(过度评论的)代码片段对任何希望开始使用 pthreads 的人有所帮助。
- 交换
PS 系统信息:debian 64 位 arch 上的 gcc
代码片段 1(已加入可加入的线程):
/* Running this multiple times with valgrind, I sometimes end with :
- no errors (proper malloc/free balance)
- 4 extra malloc vs free (most frequently)
The number of mallocs() is more conservative and depends on the number of threads.
*/
#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS macros & the likes */
#include <stdio.h> /* printf() & the likes */
#include <pthread.h> /* test subject */
#define MAX_THREADS 100 /* Number of threads */
pthread_attr_t tattr; /* Thread attribute */
pthread_t workers[MAX_THREADS]; /* All the threads spawned by the main() thread */
/* A mock container structure to pass arguments around */
struct args_for_job_t {
int tid;
int status;
};
/* The job each worker will perform upon creation */
void *job(void *arg)
{
/* Cast arguments in a proper container */
struct args_for_job_t *container;
container = (struct args_for_job_t *)arg;
/* A mock job */
printf("[TID - %d]\n", container->tid);
/* Properly exit with status code tid */
pthread_exit((void *)(&container->status));
}
int main ()
{
int return_code; /* Will hold return codes */
void *return_status; /* Will hold return status */
int tid; /* Thread id */
struct args_for_job_t args[MAX_THREADS]; /* For thread safeness */
/* Initialize and set thread joinable attribute */
pthread_attr_init(&tattr);
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
/* Spawn detached threads */
for (tid = 0; tid < MAX_THREADS; tid++)
{
args[tid].tid = tid;
args[tid].status = tid;
return_code = pthread_create(&workers[tid], &tattr, job, (void *)(&args[tid]));
if (return_code != 0) { printf("[ERROR] Thread creation failed\n"); return EXIT_FAILURE; }
}
/* Free thread attribute */
pthread_attr_destroy(&tattr);
/* Properly join() all workers before completion */
for(tid = 0; tid < MAX_THREADS; tid++)
{
return_code = pthread_join(workers[tid], &return_status);
if (return_code != 0)
{
printf("[ERROR] Return code from pthread_join() is %d\n", return_code);
return EXIT_FAILURE;
}
printf("Thread %d joined with return status %d\n", tid, *(int *)return_status);
}
return EXIT_SUCCESS;
}
代码片段 2(创建后分离的线程):
/* Running this multiple times with valgrind, I sometimes end with :
- no errors (proper malloc/free balance)
- 1 extra malloc vs free (most frequently)
Most surprisingly, it seems there is a random amount of overall mallocs
*/
#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS macros & the likes */
#include <stdio.h> /* printf() & the likes */
#include <pthread.h> /* test subject */
#include <unistd.h>
#define MAX_THREADS 100 /* Number of threads */
pthread_attr_t tattr; /* Thread attribute */
pthread_t workers[MAX_THREADS]; /* All the threads spawned by the main() thread */
/* A mock container structure to pass arguments around */
struct args_for_job_t {
int tid;
};
/* The job each worker will perform upon creation */
void *job(void *arg)
{
/* Cast arguments in a proper container */
struct args_for_job_t *container;
container = (struct args_for_job_t *)arg;
/* A mock job */
printf("[TID - %d]\n", container->tid);
/* For the sake of returning something, not necessary */
return NULL;
}
int main ()
{
int return_code; /* Will hold return codes */
int tid; /* Thread id */
struct args_for_job_t args[MAX_THREADS]; /* For thread safeness */
/* Initialize and set thread joinable attribute */
pthread_attr_init(&tattr);
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
/* Spawn detached threads */
for (tid = 0; tid < MAX_THREADS; tid++)
{
args[tid].tid = tid;
return_code = pthread_create(&workers[tid], &tattr, job, (void *)(&args[tid]));
if (return_code != 0) { printf("[ERROR] Thread creation failed\n"); return EXIT_FAILURE; }
/* Detach worker after creation */
pthread_detach(workers[tid]);
}
/* Free thread attribute */
pthread_attr_destroy(&tattr);
/* Delay main() completion until all detached threads finish their jobs. */
usleep(100000);
return EXIT_SUCCESS;
}
代码片段 3(创建时分离的线程):
/* Running this multiple times with valgrind, I sometimes end with :
- no errors (proper malloc/free balance)
- 1 extra malloc vs free (most frequently)
Most surprisingly, it seems there is a random amount of overall mallocs
*/
#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS macros & the likes */
#include <stdio.h> /* printf() & the likes */
#include <pthread.h> /* test subject */
#define MAX_THREADS 100 /* Number of threads */
pthread_attr_t tattr; /* Thread attribute */
pthread_t workers[MAX_THREADS]; /* All the threads spawned by the main() thread */
/* A mock container structure to pass arguments around */
struct args_for_job_t {
int tid;
};
/* The job each worker will perform upon creation */
void *job(void *arg)
{
/* Cast arguments in a proper container */
struct args_for_job_t *container;
container = (struct args_for_job_t *)arg;
/* A mock job */
printf("[TID - %d]\n", container->tid);
/* For the sake of returning something, not necessary */
return NULL;
}
int main ()
{
int return_code; /* Will hold return codes */
int tid; /* Thread id */
struct args_for_job_t args[MAX_THREADS]; /* For thread safeness */
/* Initialize and set thread detached attribute */
pthread_attr_init(&tattr);
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
/* Spawn detached threads */
for (tid = 0; tid < MAX_THREADS; tid++)
{
args[tid].tid = tid;
return_code = pthread_create(&workers[tid], &tattr, job, (void *)(&args[tid]));
if (return_code != 0) { printf("[ERROR] Thread creation failed\n"); return EXIT_FAILURE; }
}
/* Free thread attribute */
pthread_attr_destroy(&tattr);
/* Delay main() completion until all detached threads finish their jobs. */
usleep(100000);
return EXIT_SUCCESS;
}
代码片段 1 的 Valgrind 输出(加入的线程和内存泄漏)
==27802==
==27802== HEAP SUMMARY:
==27802== in use at exit: 1,558 bytes in 4 blocks
==27802== total heap usage: 105 allocs, 101 frees, 28,814 bytes allocated
==27802==
==27802== Searching for pointers to 4 not-freed blocks
==27802== Checked 104,360 bytes
==27802==
==27802== 36 bytes in 1 blocks are still reachable in loss record 1 of 4
==27802== at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==27802== by 0x400894D: _dl_map_object (dl-load.c:162)
==27802== by 0x401384A: dl_open_worker (dl-open.c:225)
==27802== by 0x400F175: _dl_catch_error (dl-error.c:178)
==27802== by 0x4013319: _dl_open (dl-open.c:639)
==27802== by 0x517F601: do_dlopen (dl-libc.c:89)
==27802== by 0x400F175: _dl_catch_error (dl-error.c:178)
==27802== by 0x517F6C3: __libc_dlopen_mode (dl-libc.c:48)
==27802== by 0x4E423BB: pthread_cancel_init (unwind-forcedunwind.c:53)
==27802== by 0x4E4257B: _Unwind_ForcedUnwind (unwind-forcedunwind.c:130)
==27802== by 0x4E4069F: __pthread_unwind (unwind.c:130)
==27802== by 0x4E3AFF4: pthread_exit (pthreadP.h:265)
==27802==
==27802== 36 bytes in 1 blocks are still reachable in loss record 2 of 4
==27802== at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==27802== by 0x400B7EC: _dl_new_object (dl-object.c:161)
==27802== by 0x4006805: _dl_map_object_from_fd (dl-load.c:1051)
==27802== by 0x4008699: _dl_map_object (dl-load.c:2568)
==27802== by 0x401384A: dl_open_worker (dl-open.c:225)
==27802== by 0x400F175: _dl_catch_error (dl-error.c:178)
==27802== by 0x4013319: _dl_open (dl-open.c:639)
==27802== by 0x517F601: do_dlopen (dl-libc.c:89)
==27802== by 0x400F175: _dl_catch_error (dl-error.c:178)
==27802== by 0x517F6C3: __libc_dlopen_mode (dl-libc.c:48)
==27802== by 0x4E423BB: pthread_cancel_init (unwind-forcedunwind.c:53)
==27802== by 0x4E4257B: _Unwind_ForcedUnwind (unwind-forcedunwind.c:130)
==27802==
==27802== 312 bytes in 1 blocks are still reachable in loss record 3 of 4
==27802== at 0x4C29DB4: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==27802== by 0x4010B59: _dl_check_map_versions (dl-version.c:300)
==27802== by 0x4013E1F: dl_open_worker (dl-open.c:268)
==27802== by 0x400F175: _dl_catch_error (dl-error.c:178)
==27802== by 0x4013319: _dl_open (dl-open.c:639)
==27802== by 0x517F601: do_dlopen (dl-libc.c:89)
==27802== by 0x400F175: _dl_catch_error (dl-error.c:178)
==27802== by 0x517F6C3: __libc_dlopen_mode (dl-libc.c:48)
==27802== by 0x4E423BB: pthread_cancel_init (unwind-forcedunwind.c:53)
==27802== by 0x4E4257B: _Unwind_ForcedUnwind (unwind-forcedunwind.c:130)
==27802== by 0x4E4069F: __pthread_unwind (unwind.c:130)
==27802== by 0x4E3AFF4: pthread_exit (pthreadP.h:265)
==27802==
==27802== 1,174 bytes in 1 blocks are still reachable in loss record 4 of 4
==27802== at 0x4C29DB4: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==27802== by 0x400B57D: _dl_new_object (dl-object.c:77)
==27802== by 0x4006805: _dl_map_object_from_fd (dl-load.c:1051)
==27802== by 0x4008699: _dl_map_object (dl-load.c:2568)
==27802== by 0x401384A: dl_open_worker (dl-open.c:225)
==27802== by 0x400F175: _dl_catch_error (dl-error.c:178)
==27802== by 0x4013319: _dl_open (dl-open.c:639)
==27802== by 0x517F601: do_dlopen (dl-libc.c:89)
==27802== by 0x400F175: _dl_catch_error (dl-error.c:178)
==27802== by 0x517F6C3: __libc_dlopen_mode (dl-libc.c:48)
==27802== by 0x4E423BB: pthread_cancel_init (unwind-forcedunwind.c:53)
==27802== by 0x4E4257B: _Unwind_ForcedUnwind (unwind-forcedunwind.c:130)
==27802==
==27802== LEAK SUMMARY:
==27802== definitely lost: 0 bytes in 0 blocks
==27802== indirectly lost: 0 bytes in 0 blocks
==27802== possibly lost: 0 bytes in 0 blocks
==27802== still reachable: 1,558 bytes in 4 blocks
==27802== suppressed: 0 bytes in 0 blocks
==27802==
==27802== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
--27802--
--27802-- used_suppression: 2 dl-hack3-cond-1
==27802==
==27802== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
代码片段 1 的 Valgrind 输出(没有内存泄漏,稍后运行几次)
--29170-- Discarding syms at 0x64168d0-0x6426198 in /lib/x86_64-linux-gnu/libgcc_s.so.1 due to munmap()
==29170==
==29170== HEAP SUMMARY:
==29170== in use at exit: 0 bytes in 0 blocks
==29170== total heap usage: 105 allocs, 105 frees, 28,814 bytes allocated
==29170==
==29170== All heap blocks were freed -- no leaks are possible
==29170==
==29170== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
--29170--
--29170-- used_suppression: 2 dl-hack3-cond-1
==29170==
==29170== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
最佳答案
当你的线程被分离时,你有一个错误,导致未定义的行为。
在 main 中你有这行代码:
struct args_for_job_t args[MAX_THREADS];
您将指针交给您的工作线程。
然后main()就到了这部分
pthread_exit(NULL);
并且 main() 不再存在,但您仍然可能有工作线程,它访问上面的 args
数组,该数组位于 main() 的堆栈上 - 它不再存在。在某些运行中,您的工作线程可能会在 main() 结束之前全部完成,但在其他运行中则不会。
关于c pthreads + valgrind = 内存泄漏 : why?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15207762/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!