Pthread线程基础学习

article/2025/9/18 9:45:16

后面会尝试使用冰搜和goole搜索来学习技术,互联网上知识的学习也是符合二八定律的,既然如此,我们何不去选择最好的文章呢。
文章参考:
https://randu.org/tutorials/threads/
http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html
https://blog.csdn.net/stpeace/article/details/79575493

一、多线程相关API学习

线程的学习主要包括三方面:线程管理(创建、分离、joinable以及设置线程属性等);互斥锁(创建、销毁、lock 和unlock等);条件变量(conditon variable)。
这里记录一些重要的API作为记录学习吧。

线程创建
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

参数:

pthread_t *thread: the actual thread object that contains pthread id
pthread_attr_t *attr: attributes to apply to this thread
void *(*start_routine)(void *): the function this thread executes
void *arg: arguments to pass to thread function above

线程创建时应保证线程ID thread被成功创建(检查返回值);线程属性attr默认值为NULL,可设置为其他属性;start_routine是创建线程后所执行的函数体;arg是传入的参数。

线程等待和终止
void pthread_exit(void *value_ptr);
int pthread_join(pthread_t thread, void **value_ptr);

pthread_exit() 终止线程,并且提供指针变量*value_ptrpthread_join()调用
pthread_join() 阻塞调用线程调用,并等待线程结束,得到可选返回值*value_ptr

//1. 确保检查重要函数返回值
//2. pthread_create()的第二个参数为NULL,属性为默认属性(比如joinable)
//3. 参数传递
//4. pthread_join()是阻塞的,可接收pthread_exit()返回的线程结果信息
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>#define NUM_THREADS  2//thread argument struct
typedef struct _thread_data {int tid;double studff;
} thread_data;//thread function
void *thr_func(void *arg) {thread_data *data = (thread_data *)arg;printf("from thr_func, thread id:%d\n",data->tid);pthread_exit(NULL);
}int main() {pthread_t thr[NUM_THREADS];int i,rc;//thread_data argument arraythread_data thr_data[NUM_THREADS];//create threadsfor(i=0; i<NUM_THREADS; ++i) {thr_data[i].tid = i;if((rc = pthread_create(&thr[i],NULL,thr_func,&thr_data[i]))) {fprintf(stderr,"error:pthread_create,rc: %d\n",rc);return EXIT_FAILURE;}}//block untill all threads completefor(i=0; i<NUM_THREADS; ++i) {pthread_join(thr[i],NULL);}return 0;
}
线程属性

属性的初始化、属性的设置set、属性的获取get

int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope);
int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr);
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);

示例:

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define NUM_THREADS  2//thread argument struct
typedef struct _thread_data {int tid;double studff;
} thread_data;//thread function
void *thr_func(void *arg) {thread_data *data = (thread_data *)arg;printf("from thr_func, thread id:%d\n",data->tid);pthread_exit(NULL);
}int main() {pthread_t thr[NUM_THREADS];int i,rc;//thread_data argument arraythread_data thr_data[NUM_THREADS];//initialize and set thread datachedpthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//create threadsfor(i=0; i<NUM_THREADS; ++i) {thr_data[i].tid = i;if((rc = pthread_create(&thr[i],&attr,thr_func,&thr_data[i]))) {fprintf(stderr,"error:pthread_create,rc: %d\n",rc);return EXIT_FAILURE;}}pthread_attr_destroy(&attr);sleep(5);return 0;
}

其实,这个代码和上一个代码是类似的:
线程一得等到pthread_join来释放系统资源,线程一的线程函数一结束就自动释放资源
总之为了在使用 pthread 时避免线程的资源在线程结束时不能得到正确释放,从而避免产生潜在的内存泄漏问题,在对待线程结束时,要确保该线程处于 detached 状态,否着就需要调用 pthread_join() 函数来对其进行资源回收。

线程互斥锁
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);//动态初始化
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; //静态初始化//acquire a lock on the specified mutex variable. If the mutex is already locked by another thread, 
//this call will block the calling thread until the mutex is unlocked.
int pthread_mutex_lock(pthread_mutex_t *mutex);
// attempt to lock a mutex or will return error code if busy. Useful for preventing deadlock conditions.
int pthread_mutex_trylock(pthread_mutex_t *mutex);
//unlock a mutex variable. An error is returned if mutex is already unlocked or owned by another thread.
int pthread_mutex_unlock(pthread_mutex_t *mutex);

示例

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>void * updateCounter(void*);pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int counter =0;int main(){int rc1,rc2;pthread_t thread1,thread2;if( (rc1=pthread_create( &thread1, NULL, &updateCounter, NULL)) ){printf("Thread creation failed: %d\n", rc1);}if( (rc2=pthread_create( &thread2, NULL, &updateCounter, NULL)) ){printf("Thread creation failed: %d\n", rc2);}/* Wait till threads are complete before main continues.*/pthread_join( thread1, NULL);pthread_join( thread2, NULL);return 0;}void * updateCounter(void*){pthread_mutex_lock( &mutex1 );counter++;printf("Counter value: %d\n",counter);pthread_mutex_unlock( &mutex1 );
}
线程条件变量
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);

示例:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>pthread_mutex_t count_mutex     = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  condition_var   = PTHREAD_COND_INITIALIZER;void *functionCount1(void*);
void *functionCount2(void*);
int  count = 0;
#define COUNT_DONE  10
#define COUNT_HALT1  3
#define COUNT_HALT2  6int main()
{pthread_t thread1, thread2;pthread_create( &thread1, NULL, &functionCount1, NULL);pthread_create( &thread2, NULL, &functionCount2, NULL);pthread_join( thread1, NULL);pthread_join( thread2, NULL);printf("Final count: %d\n",count);exit(EXIT_SUCCESS);
}// Write numbers 1-3 and 8-10 as permitted by functionCount2()
void *functionCount1(void*)
{for(;;){// Lock mutex and then wait for signal to relase mutexpthread_mutex_lock( &count_mutex );// Wait while functionCount2() operates on count// mutex unlocked if condition varialbe in functionCount2() signaled.pthread_cond_wait( &condition_var, &count_mutex );count++;printf("Counter value functionCount1: %d\n",count);pthread_mutex_unlock( &count_mutex );if(count >= COUNT_DONE) return(NULL);}
}// Write numbers 4-7
void *functionCount2(void*)
{for(;;){pthread_mutex_lock( &count_mutex );if( count < COUNT_HALT1 || count > COUNT_HALT2 ){// Condition of if statement has been met. // Signal to free waiting thread by freeing the mutex.// Note: functionCount1() is now permitted to modify "count".pthread_cond_signal( &condition_var );}else{count++;printf("Counter value functionCount2: %d\n",count);}pthread_mutex_unlock( &count_mutex );if(count >= COUNT_DONE) return(NULL);}}

在这里插入图片描述
标准模板以及解释:

void *thr_func1(void *arg) {/* thread code blocks here until MAX_COUNT is reached */pthread_mutex_lock(&count_lock);while (count < MAX_COUNT) {pthread_cond_wait(&count_cond, &count_lock);}pthread_mutex_unlock(&count_lock);/* proceed with thread execution */pthread_exit(NULL);
}/* some other thread code that signals a waiting thread that MAX_COUNT has been reached */
void *thr_func2(void *arg) {pthread_mutex_lock(&count_lock);/* some code here that does interesting stuff and modifies count */if (count == MAX_COUNT) {pthread_mutex_unlock(&count_lock);pthread_cond_signal(&count_cond);} else {pthread_mutex_unlock(&count_lock);}pthread_exit(NULL);
} 

为什么这里要记录一些呢?pthread_cond_wait要使用while而不是if,解释如下:

在这里插入图片描述

pthread Barrier及其它
int pthread_barrier_init(pthread_barrier_t *barrier, pthread_barrierattr_t *barrier_attr, unsigned int count);pthread_barrier_t barrier = PTHREAD_BARRIER_INITIALIZER(count);
int pthread_barrier_wait(pthread_barrier_t *barrier);pthread_kill() can be used to deliver signals to specific threads.
pthread_self() returns a handle on the calling thread.
pthread_equal() compares for equality between two pthread ids
pthread_once() can be used to ensure that an initializing function within a thread is only run once.

二、Pthread创建线程后必须使用join或detach释放线程资源

When a joinable thread terminates, its memory resources (thread descriptor and stack) are
not deallocated until another thread performs pthread_join on it.
Therefore, pthread_join must be called once for each joinable thread created to avoid memory leaks.

有问题的代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>void* threadFunc(void* p)  
{  char szTest[1024 * 32] = {0};return NULL;  
}  int main(void)
{pthread_t id;  pthread_create (&id, NULL, threadFunc, NULL);  sleep(1);printf("\n— main End —- \n");return 0;
}

在这里插入图片描述
解决方法有三个:

  1. 线程里面调用 pthread_detach(pthread_self()) 这个方法最简单
  2. 在创建线程的设置PTHREAD_CREATE_DETACHED属性
  3. 创建线程后用 pthread_join() 一直等待子线程结束。

方法一:

void* threadFunc(void* p)  
{   //注意1:pthread_detach(pthread_self());char szTest[1024 * 32] = {0};return NULL;  
}  
int main(void)
{pthread_t id;  //注意2:参数2为NULLpthread_create (&id, NULL, threadFunc, NULL);  sleep(1);printf("\n— main End —- \n");return 0;
}

方法二:

void* threadFunc(void* p)  
{  char szTest[1024 * 32] = {0};return NULL;  
}  int main(void)
{   //注意1:pthread_attr_t attr;	pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);pthread_t id;  //注意2:参数2为attrpthread_create (&id, &attr, threadFunc, NULL);  sleep(1);printf("\n— main End —- \n");return 0;
}

方法三:

void* threadFunc(void* p)  
{  char szTest[1024 * 32] = {0};return NULL;  
}  int main(void)
{pthread_t id;  //注意1:参数2为NULLpthread_create (&id, NULL, threadFunc, NULL);  //注意2:blockpthread_join(id, NULL);sleep(1);printf("\n— main End —- \n");return 0;
}

再次检测:
在这里插入图片描述

综上,无论是pthread线程库,还是最近我在使用C++11线程,对于joinable线程,如果最后没有添加t.join(),就会coredump。本质就是要考虑内存泄漏问题,我们可以使用valgrind检测查看。


http://chatgpt.dhexx.cn/article/eimt6FR4.shtml

相关文章

pthread 线程创建

1.1代码 #include <pthread.h> #include <stdio.h> #include <unistd.h>static int my_thread_func (void *data) {while(1){sleep(1);} }main() {pthread_t tid;int ret;// 1.创建接收线程ret pthread_create(&tid, NULL,my_thread_func, NULL);if(ret…

C语言pthread.h运用

线程概念 什么是多线程&#xff0c;提出这个问题的时候&#xff0c;我还是很老实的拿出操作系统的书&#xff0c;按着上面的话敲下“为了减少进程切换和创建开销&#xff0c;提高执行效率和节省资源&#xff0c;我们引入了线程的概念&#xff0c;与进程相比较&#xff0c;线程…

linux pthread头文件,pthread t 头文件_uint8 t 头文件_pthread t 头文件

多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序。一般情况下,两种类型的多任务处理:基于进程和基于线程。 多线程程序包含可以同时运行的两个或多个部分。这样的程序中的每个部分称为一个线程,每个线程定义了一个单独的执行路径。 本…

Day 55 Linux 线程控制语句pthread_exit pthread_join pthread_detach pthread_cancel 线程属性

目录 1. 线程控制语句 1.1pthread_exit函数 1.2pthread_join函数 1.3pthread_detach函数 1.4pthread_cancel函数 控制原语对比 2. 线程属性 2.1线程属性初始化 2.2线程的分离状态 2.3线程使用注意事项 1. 线程控制语句 1.1pthread_exit函数 将单个当前线程退出 void…

pthread 线程基本函数

文章目录 一、int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);二、int pthread_join(pthread_t tid, void **thread_return);三、int pthread_detach(pthread_t tid);四、void pthread_exit(void *retval);五、int …

pthread

POSIX线程&#xff08;POSIX threads&#xff09;&#xff0c;简称Pthreads&#xff0c;是线程的POSIX标准。该标准定义了创建和操纵线程的一整套API。在类Unix操作系统&#xff08;Unix、Linux、Mac OS X等&#xff09;中&#xff0c;都使用Pthreads作为操作系统的线程。 1、p…

线程以及pthread库的使用

一.什么是线程 你可以想象你一边听歌一边打游戏&#xff0c;如果是操作系统会怎么做呢&#xff1f;先执行 ListenMusic 再执行 PlayGame&#xff0c;还是先执行 PlayGame 再执行 ListenMusic 呢&#xff1f;好像都不太合适。为了实现这个目的&#xff0c;就需要引入线程这个概念…

多线程02---pThread简介

1.简介 pthread 是属于 POSIX 多线程开发框架。它是c语言提供的一个跨平台的多线程解决方案。由于其在iOS编程中&#xff0c;操作比较麻烦&#xff0c;一般不用&#xff0c;这里介绍仅仅作为了解。 2.pthread的使用 通过以下函数创建pthread&#xff0c;在C语言中类型的结尾…

Qt 无法识别的外部符号.无法解析的外部符号

原因: 很多博客都说了这个原因,是因为后续在自己的类中,引入Q_OBJECT , 导致vs无法自动生成 moc_XXX.cpp类似的文件, 编译时候,找不到导致的(符号链接). 他人解决办法: 看了很多博客,说用moc_xx.exe, 重新生成对应的.h头文件,一下,就可以了;有的建议重新把类添加一下,然后清…

Qt项目 无法解析的外部符号_WinMainCRTStartup

1、无法解析的外部符号_WinMainCRTStartup 在编译Qt项目的时候突然说找不到_WinMainCRTStartup函数&#xff0c;_WinMainCRTStartup是Qt的主函数。找不到可能是main函数不在工程中。 选中main.cpp点击编译 点击移除再重新添加

QT无法解析的外部符号问题

moc_widget.obj:-1: error: LNK2019: 无法解析的外部符号 "private: void __thiscall Widget::on_pushButton_6_clicked(void)" (?on_pushButton_6_clickedWidgetAAEXXZ)&#xff0c;该符号在函数 "private: static void __cdecl Widget::qt_static_metacall(c…

QT疑难解决:无法解析的外部符号

无法解析的外部符号 _imp_XXXXXXXXX 出现字符_imp&#xff0c;说明不是真正的静态库&#xff0c;而是某个动态库的导入库&#xff0c;导入函数和自己不同名&#xff0c;所以加了字符_imp。 引入相应库 打开MSDN搜索函数xxxxx&#xff1a;http://msdn.microsoft.com/en-us/dn…

CUDA编程时遇到无法解析外部符号threadIdx或blockIdx问题的解决办法

在CUDA编程时遇到出现无法解析外部符号threadIdx或blockIdx问题的解决办法 在CUDA编程之前要确保工程项目的配置属性一致性如图一所示。然后点击项目—>属性确保配置属性无误。 VC 目录 可执行文件目录&#xff1a;…\NVIDIA GPU Computing Toolkit\CUDA\v10.2\bin 包含目…

LNK2019 无法解析的外部符号

LNK 2019 遇到了很多次这个错误&#xff0c;会持续更新遇到该错误产生的原因和解决方法 这个错误是由于我们调用的函数所定义的某个文件在编译时没有正确链接导致的&#xff0c;错误显示如下&#xff1a; 然后根据错误提示找到该函数 ImGui_ImplOpenGL3_Shutdown();ImGui_Impl…

无法解析的外部符号解决方法

步骤1&#xff1a; 按无法解析的顺序来解决问题 比如有两个无法解析&#xff0c;先解决第一个。 步骤2&#xff1a; 点击LNK2001,会跳转到网页&#xff0c;网页会提示哪些无法解析的问题是由哪个无法解析的错误引起的&#xff0c;这样可以减少解决无法解析的错误。 步骤3. …

无法解析的外部符号问题小结

问题1&#xff1a;在编写通信相关程序中&#xff0c;引用了一个静态库&#xff08;该静态库编译没有问题&#xff0c;并被其他项目引用&#xff09;&#xff0c;该库是对SOCKET的一个封装。基本结构如下&#xff1a; 在属性中添加了该库的引用后&#xff0c;编译仍然报错&#…

无法解析的外部符号main

今天在写程序的时候遇到个问题&#xff1a; 然后就去看了相应的解决方法 发现都不管用&#xff1a; 1.不是文件名.c或.cpp的问题 2.不是没有包含相应头文件的问题 3.不是写的控制台程序而使用的Windows连接程序&#xff08;Winmain&#xff09; 最后发现是因为在刚开始打开项…

无法解析的外部符号xxx 该符号在函数xxx中被引用

无法解析的外部符号xxx 该符号在函数xxx中被引用 更多相关错误可查看&#xff1a;https://blog.csdn.net/weixin_44120025/article/details/115279563 下面主要讲述一个解决方案中包含多个项目且它们之间互相引用的情况。 在一个解决方案已经有多个项目的情况下创建一个项目&am…

Visual Studio 2022配置GAMP出现 LNK2019无法解析外部符号_imp_timeGetTime@0

#vs2022配置GAMP 使用visual studio 2022配置软件GAMP的过程可以参考vs2019配置GAMP的详细过程。 在vs2022按照vs2019配置过程后&#xff0c;生成解决方案时&#xff0c;出现了LNK2019 无法解析的外部符号 _imp_timeGetTim0, 函数_tickget中引用了该符号。 解决方法如下&#…

跟着LearnOpenGLCN学习OpenGL配置GLAD环境时出现无法解析外部符号问题的解决

根据LearnOpenGLCN里的步骤&#xff1a; 1.将解压下来的glad和KHR直接复制到glfw-3.3.4.bin.WIN32的include里。 2.glad.c放到工程文件中去。 3.GLFW和GLAD配置环境 第一步&#xff1a; 第二步&#xff1a; 在配置环境后&#xff0c;运行调用窗口代码&#xff0c;出现以下错…