什么是多线程编程?
1、线程和进程的区别
进程是指正在运行的程序,它拥有独立的内存空间和系统资源,不同进程之间的数据不共享。
线程是进程内的执行单元,它与同一进程内的其他线程共享进程的内存空间和系统资源。
2、多线程的优势和应用场景
多线程是一种并发编程方式,它的优势包括:
- 提高程序的响应速度和运行效率(多核CPU下的多线程)
- 充分利用CPU资源,提高系统的利用率
- 支持多个任务并行执行,提高程序的可扩展性和可维护性
Linux下的多线程编程
Linux下C语言多线程编程依赖于pthread多线程库。pthread库是Linux的多线程库,是POSIX标准线程API的实现,它提供了一种创建和操纵线程的方法,以及一些同步机制,如互斥锁、条件变量等。
头文件:
`#include < pthread.h >
`
编译链接需要链接链接库 pthread。
一、线程的基本操作
1、pthread_create
/**
* @brief 创建一个线程
*
* Detailed function description
*
* @param[in] thread: 一个指向线程标识符的指针,线程调用后,该值被设置为线程ID;pthread_t为unsigned long int
* @param[in] attr: 用来设置线程属性
* @param[in] start_routine: 线程函数体,线程创建成功后,thread 指向的内存单元从该地址开始运行
* @param[in] arg: 传递给线程函数体的参数
*
* @return 线程创建成功,则返回0,失败则返回错误码,并且 thread 内容是未定义的
*/
int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void*(*start_routine)(void*), void* arg);
例子test.c:创建一个线程,每1s打印一次。
`#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < pthread.h >
static pthread_t s_thread_id;
static unsigned char s_thread_running = 0;
void *thread_fun(void *arg)
{
s_thread_running = 1;
while (s_thread_running)
{
printf("thread run...\\n");
sleep(1);
}
pthread_exit(NULL);
}
int main(void)
{
int ret = 0;
printf("Before Thread\\n");
ret = pthread_create(&s_thread_id, NULL, thread_fun, NULL);
if (ret != 0)
{
printf("thread_create error!\\n");
exit(EXIT_FAILURE);
}
ret = pthread_join(s_thread_id, NULL); ///< 阻塞等待线程结束
if (ret != 0)
{
printf("pthread_join error!\\n");
exit(EXIT_FAILURE);
}
printf("After Thread\\n");
exit(EXIT_SUCCESS);
}
`
编译、运行:
`gcc test.c -o test -lpthread
`
2、pthread_join
`/**
* @brief 等待某个线程结束
*
* Detailed function description: 这是一个线程阻塞函数,调用该函数则等到线程结束才继续运行
*
* @param[in] thread: 某个线程的ID
* @param[in] retval: 用于获取线程 start_routine 的返回值
*
* @return 线程创建成功,则返回0,失败则返回错误码,并且 thread 内容是未定义的
*/
int pthread_join(pthread_t thread, void **retval);
`
例子test.c:创建一个线程,进行一次加法运算就返回。
`#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < pthread.h >
static pthread_t s_thread_id;
static unsigned char s_thread_running = 0;
void *thread_fun(void *arg)
{
static int res = 0;
int a = 1, b = 2;
res = a + b;
sleep(1);
printf("thread run, a + b = %d, addr = %p\\n", res, &res);
pthread_exit(&res);
}
int main(void)
{
int ret = 0;
int *retval = NULL;
printf("Before Thread\\n");
ret = pthread_create(&s_thread_id, NULL, thread_fun, NULL);
if (ret != 0)
{
printf("pthread_create error!\\n");
exit(EXIT_FAILURE);
}
ret = pthread_join(s_thread_id, (void **)&retval); ///< 阻塞等待线程结束
if (ret != 0)
{
printf("pthread_join error!\\n");
exit(EXIT_FAILURE);
}
if (retval != NULL)
{
printf("After Thread, retval = %d, addr = %p\\n", (int)*retval, retval);
}
exit(EXIT_SUCCESS);
}
`
编译、运行:
3、pthread_exit
`/**
* @brief 退出线程
*
* Detailed function description
*
* @param[in] retval: 它指向的数据将作为线程退出时的返回值
*
* @return void
*/
void pthread_exit(void *retval);
`
- 线程将指定函数体中的代码执行完后自行结束;
- 线程执行过程中,被同一进程中的其它线程(包括主线程)强制终止;
- 线程执行过程中,遇到 pthread_exit() 函数结束执行。
例子test.c:创建一个线程,每个1s打印一次,打印超过5次时调用pthread_exit退出。
#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < pthread.h >
static pthread_t s_thread_id;
static unsigned char s_thread_running = 0;
const static char *thread_exit_str = "thread_exit ok!";
void *thread_fun(void *arg)
{
static int cnt = 0;
s_thread_running = 1;
while (s_thread_running)
{
cnt++;
if (cnt > 5)
{
pthread_exit((void*)thread_exit_str);
}
printf("thread run...\\n");
sleep(1);
}
pthread_exit(NULL);
}
int main(void)
{
int ret = 0;
void *thread_res = NULL;
printf("Before Thread\\n");
ret = pthread_create(&s_thread_id, NULL, thread_fun, NULL);
if (ret != 0)
{
printf("thread_create error!\\n");
exit(EXIT_FAILURE);
}
ret = pthread_join(s_thread_id, (void**)&thread_res);
if (ret != 0)
{
printf("thread_join error!\\n");
exit(EXIT_FAILURE);
}
printf("After Thread, thread_res = %s\\n", (char*)thread_res);
exit(EXIT_SUCCESS);
}
编译、运行:
使用return退出线程与使用pthread_exit退出线程的区别?
return为通用的函数退出操作,pthread_exit专用与线程,既然pthread库有提供专门的函数,自然用pthread_exit会好些,虽然使用return也可以。
看看return退出线程与使用pthread_exit退出线程的具体区别:退出主线程。使用pthread_exit退出主线程只会终止当前线程,不会影响进程中其它线程的执行;使用return退出主线程,主线程退出执行很快,所有线程都会退出。
例子:使用pthread_exit退出主线程
`#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < pthread.h >
static pthread_t s_thread_id;
static unsigned char s_thread_running = 0;
const static char *thread_exit_str = "thread_exit ok!";
void *thread_fun(void *arg)
{
sleep(1);
printf("thread_fun run...\\n");
pthread_exit(NULL);
}
int main(void)
{
int ret = 0;
void *thread_res = NULL;
printf("Before Thread\\n");
ret = pthread_create(&s_thread_id, NULL, thread_fun, NULL);
if (ret != 0)
{
printf("thread_create error!\\n");
exit(EXIT_FAILURE);
}
printf("main thread exit\\n");
pthread_exit(NULL);
}
`
编译、运行:
例子:使用return退出主线程
`#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < pthread.h >
static pthread_t s_thread_id;
static unsigned char s_thread_running = 0;
const static char *thread_exit_str = "thread_exit ok!";
void *thread_fun(void *arg)
{
sleep(1);
printf("thread_fun run...\\n");
pthread_exit(NULL);
}
int main(void)
{
int ret = 0;
void *thread_res = NULL;
printf("Before Thread\\n");
ret = pthread_create(&s_thread_id, NULL, thread_fun, NULL);
if (ret != 0)
{
printf("thread_create error!\\n");
exit(EXIT_FAILURE);
}
printf("main thread exit\\n");
return 0;
}
`
编译、运行:
4、pthread_self
`/**
* @brief 用来获取当前线程ID
*
* Detailed function description
*
* @param[in] void
*
* @return 返回线程id
*/
pthread_t pthread_self(void);
`
例子:
#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < pthread.h >
static pthread_t s_thread_id;
static unsigned char s_thread_running = 0;
const static char *thread_exit_str = "thread_exit ok!";
void *thread_fun(void *arg)
{
static int cnt = 0;
s_thread_running = 1;
while (s_thread_running)
{
cnt++;
if (cnt > 5)
{
pthread_exit((void*)thread_exit_str);
}
printf("thread run(tid = %ld)...\\n", pthread_self());
sleep(1);
}
pthread_exit(NULL);
}
int main(void)
{
int ret = 0;
void *thread_res = NULL;
pid_t pid = getpid();
printf("pid = %d\\n", pid);
printf("Before Thread\\n");
ret = pthread_create(&s_thread_id, NULL, thread_fun, NULL);
if (ret != 0)
{
printf("thread_create error!\\n");
exit(EXIT_FAILURE);
}
ret = pthread_join(s_thread_id, (void**)&thread_res);
if (ret != 0)
{
printf("thread_join error!\\n");
exit(EXIT_FAILURE);
}
printf("After Thread, thread_res = %s\\n", (char*)thread_res);
exit(EXIT_SUCCESS);
}