Linux应用开发 - 多线程编程
定义
线程是进程中的一个独立的代码块。说白了,其实它就是个函数,只不过再也不用像以前的函数调用来调用它。而是通过
pthread_create
函数来创建它,也就是告诉内核,这个函数是个线程,今后交给你来调度了。
相关API
//创建线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
//退出线程
void pthread_exit(void *retval);
//回收线程
int pthread_join(pthread_t thread, void **retval);
//分离线程
int pthread_detach(pthread_t thread);
//取消线程
int pthread_cancel(pthread_t thread);
//获取本线程的ID
pthread_t pthread_self(void);
//判断两个线程id是否相等
int pthread_equal(pthread_t t1, pthread_t t2);
案例1
创建线程
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <error.h>
void *fun(void *arge)
{
printf("pthread new = %lu\n",(unsigned int)pthread_self());
}
int main(void)
{
pthread_t tid1;
int ret = pthread_create(&tid1,NULL,fun,NULL);
if (ret!=0)
{
perror("pthread error\n");
return -1;
/* code */
}
printf("tid_main=%lu tid_new=%lu\n",(unsigned int)pthread_self(),tid1); // tid1标识线程创建成功后指向的空间
sleep(1);//为了等会儿子线程 要不主线程一执行完就结束了
return 0;
}
这个案例仅是用于在主进程中创建一个线程
线程函数的程序在 pthread 库中,故链接时要加上参数 -lpthread。
运行结果:
tid_main=1999865600 tid_new=140696530216704
pthread new = 1991534336
函数说明:
int pthread_create( pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void ( func) (void *), void *restrict arg )
- thread:线程标识符
- attr: 线程属性设置 null表示采用默认
- start_roitine : 线程函数的启示地址、
- arg :传递给start_routine的参数
- 返回值:成功:0出错:-1
案例2
线程传参
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <error.h>
struct student
{
int age;
char name[20];
/* data */
};
void *fun(void *stu)
{
printf("pthread new = %lu\n",(unsigned int)pthread_self());
printf("name:%s\tage:%d\n",((struct student *)stu)->name,((struct student *)stu)->age);
}
int main(void)
{
struct student stu;
stu.age = 10;
memcpy(stu.name,"liming",6);
pthread_t tid1;
int ret = pthread_create(&tid1,NULL,fun,(void *)&stu);
if (ret!=0)
{
perror("pthread error\n");
return -1;
/* code */
}
printf("tid_main=%lu tid_new=%lu\n",(unsigned int)pthread_self(),tid1); // tid1标识线程创建成功后指向的空间
sleep(1);//为了等会儿子线程 要不主线程一执行完就结束了
return 0;
}
运行结果:
tid_main=3901490944 tid_new=140084251518720
pthread new = 3893159680
name:liming age:10
案例3
线程退出
终止线程执行(3种方法)
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <error.h>
#include <string.h>
#include <stdlib.h>
void *thread_fun(void *args)
{
if (strcmp("1", (char *)args) == 0)
{
printf("new thread return\n");
return (void *)1;
/* code */
}
if (strcmp("2", (char *)args) == 0)
{
printf("new thread pthread_exit\n");
pthread_exit((void *)2);
/* code */
}
if (strcmp("3", (char *)args) == 0)
{
printf("new thread exit\n");
exit(3);
}
}
int main(int argc, char *argv[])
{
int err;
pthread_t tid;
err = pthread_create(&tid, NULL, thread_fun, (void *)argv[1]);
if (err != 0)
{
printf("creat thread fail\n");
return 0;
}
sleep(1);
printf("main func\n");
return 0;
}
运行结果:
./exit1 1
new thread return
main func
return的作用是:返回到调用者处。有可能会退出进程(放在主线程时),有可能会退出线程,也有可能什么也不退出。
./exit1 2
new thread pthread_exit
main func
只退出当前子线程。注意:在主线程退出时,其它线程不会结束。同样可以执行。所以这个只字非常重要。并且,与return一样,pthread_exit退出的线程也需要调用pthread_join去回收子线程的资源(8k左右),否则服务器长时间运行会浪费资源导致无法再创建新线程。
./exit1 3
new thread exit
将进程退出,无论哪个子线程调用整个程序都将结束。
案例4
线程回收
#include <stdio.h>
#include <pthread.h>
//定义线程要执行的函数,arg 为接收线程传递过来的数据
void* Thread1(void* arg)
{
printf("hello linux\n");
return "Thread1成功执行";
}
//定义线程要执行的函数,arg 为接收线程传递过来的数据
void* Thread2(void* arg)
{
printf("李魁\n");
return "Thread2成功执行";
}
int main()
{
int res;
//创建两个线程变量
pthread_t mythread1, mythread2;
void* thread_result;
//创建 mythread1 线程,执行 Thread1() 函数
res = pthread_create(&mythread1, NULL, Thread1, NULL);
if (res != 0) {
printf("线程创建失败");
return 0;
}
//创建 mythread2 线程,执行 Thread2() 函数
res = pthread_create(&mythread2, NULL, Thread2, NULL);
if (res != 0) {
printf("线程创建失败");
return 0;
}
//阻塞主线程,直至 mythread1 线程执行结束,用 thread_result 指向接收到的返回值,阻塞状态才消除。
res = pthread_join(mythread1, &thread_result);
//输出线程执行完毕后返回的数据
printf("%s\n", (char*)thread_result);
//阻塞主线程,直至 mythread2 线程执行结束,用 thread_result 指向接收到的返回值,阻塞状态才消除。
res = pthread_join(mythread2, &thread_result);
printf("%s\n", (char*)thread_result);
printf("主线程执行完毕");
return 0;
}
运行结果:
hello linux
李魁
Thread1成功执行
Thread2成功执行
主线程执行完毕
int pthread_join(pthread_t thread, void ** retval);
函数功能:
- 接收目标线程执行结束时的返回值
- 释放目标线程占用的进程资源
thread 参数用于指定目标线程;retval 参数用于存储接收到的返回值。实际场景中,调用 pthread_join() 函数可能仅是为了及时释放目标线程占用的资源,并不想接收它的返回值,这种情况下可以将 retval 置为 NULL。
函数会一直阻塞当前线程,直至目标线程执行结束,阻塞状态才会消除。如果成功等到了目标线程执行结束(成功获取到目标线程的返回值)函数返回数字 0,否则返回非零数。
- 程序中共有 3 个线程,分别是主线程,mythread1 线程和 mythread2 线程。mythread1 线程负责执行 Thread1() 函数,mythread2 线程负责执行 Thread2() 函数。
- 主线程先后调用了两次 pthread_join() 函数,都会阻塞主线程,直至 mythread1 和 mythread2 线程执行完毕,阻塞状态才会消除。