Linux 系统编程一一线程

什么是线程
线程是 CPU 调度和分派的基本单位。线程存在于进程中,共享进程的资源。为了减少系统开销,从进程中演化出了线程。线程自己不拥有资源,但它可以去访问其所属进程的资源。

进程和线程的关系
通常在一个进程中可以包含若干个线程,它们可以利用进程的所拥有的资源。但是线程是属于进程的,而进程是拥有资源且进程间相互独立。不仅进程间可以并发执行,而且在一个进程中的多个线程之间也可以并发执行。

线程常见函数原型

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

功能:
在一个进程中创建一个新的线程,其属性由attr指定。如果attr为空,则默认属性为应使用。
参数:
thread:线程标识符地址。
attr:线程属性结构体地址。
start_routine:线程函数的入
arg:传给线程函数的参数。
返回值:
如果成功,pthread_create()函数将返回0;
否则,将返回一个错误号来指示错误。

线程等待
int pthread_join(pthread_t thread, void **value_ptr);
功能:
除非目标线程已经终止,否则pthread_join()函数将暂停调用线程的执行,直到目标线程终止为止。pthread_join函数会使调用者阻塞。

参数:
thread:被等待的线程号。
value_ptr:用来存储线程退出状态的指针的地址。

返回值
如果成功,pthread_join()函数将返回0;
否则,将返回一个错误号来指示错误。

验证pthread_join是否有线程等待(阻塞)效果。线程函数的程序在 pthread 库中,链接时要加上参数-lpthread。

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>

void *Pthread_test(void *argv)
{
	static int i_num = 55;
	sleep(2);//两秒后,将返回
	return (&i_num);
}


int main(int argc, char const *argv[])
{
	
	int ret = 0;
	pthread_t tid1;
	void *i_value = NULL;

	if ((ret = pthread_create(&tid1,NULL,Pthread_test,NULL)) != 0)
	{
		perror("pthread_create");
		exit(1);
	}

	pthread_join(tid1,&i_value); //等待线程,接收线程返回值
	printf("i_value = %d\n",*((int *)i_value));

	return 0;
}

输出结果
在这里插入图片描述线程函数传参

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>

void *Pthread_test(void *argv)
{
	int i_num = 0;
	sleep(1);
	i_num = *((int*)argv);
	printf("i_num = %d\n", i_num);
	return NULL;
}


int main(int argc, char const *argv[])
{
	
	int ret = 0;
	pthread_t tid1;
	int i_value = 66;
	if ((ret = pthread_create(&tid1,NULL,Pthread_test,(void *)&i_value)) != 0)
	{
		perror("pthread_create");
		exit(1);
	}

	pthread_join(tid1,NULL);//线程等待,接收线程返回值为NULL

	return 0;
}

输出结果
在这里插入图片描述

线程分离
int pthread_detach(pthread_t thread);
功能:
当线程终止时,可以回收线程的存储。如果线程没有终止,pthread_detach()不会导致线程终止。pthread_detach()使调用线程与当前进程分离。成为一个独立的线程,该线程终止时,系统将自动回收它的资源。
参数:
thread:线程号
返回值:
如果调用成功,pthread_detach()将返回0;
否则,将返回一个错误号来指示错误。

线程退出
void pthread_exit(void *value_ptr);
功能:
函数pthread_exit()将终止调用线程,并使value_ptr值对任何成功连接到终止线程的线程可用。
参数:
value_ptr:存储线程退出状态的指针。

注册清理函数与弹出清理函数
void pthread_cleanup_pop(int execute);
功能:
函数pthread_cleanup_pop()将删除调用线程的取消清理堆栈顶部的例程,并可选地调用它。
参数:
execute:线程清理函数执行标志位。
非 0,弹出清理函数,执行清理函数。
0,弹出清理函数,不执行清理函数。
void pthread_cleanup_push(void (routine)(void), void *arg);
功能:
将指定的取消清理处理程序例程推入调用线程的取消清理堆栈。
参数:
routine:线程清理函数的指针。
arg:传给线程清理函数的参数。

取消线程

int pthread_cancel(pthread_t thread);
功能:
请求线程被取消。目标线程的可取消状态和类型决定了取消何时生效。pthread_cancel是指取消一个正在执行线程的操作。
参数:
thread:目标线程 ID。
返回值:
如果成功,pthread_cancel()函数将返回0;
否则,将返回一个错误号来指示错误。

当线程执行以下动作时会调用清理函数:
1、调用 pthread_exit 退出线程。
2、响应其它线程的取消请求。
3、用非零 execute 调用 pthread_cleanup_pop。
无论哪种情况 pthread_cleanup_pop 都将删除上一次 pthread_cleanup_push 调用注册的清理处理函数。

调用 pthread_cleanup_pop 函数时,系统自动调用线程清理函数

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>

void cleanup_func1(void *arg)
{
	printf("cleanup_func1\n");
	printf("clean up ptr = %s\n", (char *)arg); //清理拷贝字符串
	free((char *)arg);
}

void cleanup_func2(void *arg)
{
	printf("cleanup_func2\n");
}

void *Pthread_test(void *arg)
{
	char *ptr = NULL;
	ptr = (char*)malloc(100);
	pthread_cleanup_push(cleanup_func1, (void*)(ptr));  
	pthread_cleanup_push(cleanup_func2, NULL); 
	bzero(ptr, 100); //清空缓冲区
	strcpy(ptr, "Cats love dogs");
	pthread_cleanup_pop(1);
	pthread_cleanup_pop(1);
	return NULL;
}

int main(int argc, char *argv[])
{
	pthread_t tid;
	int ret = 0;

	if ((ret = pthread_create(&tid, NULL, Pthread_test, NULL)) != 0) // 创建一个线程
	{
		perror("pthread_create");		
	}
	pthread_join(tid,NULL);//线程等待,接收线程返回值为NULL
	return 0;
}


编译结果
在这里插入图片描述

发布了131 篇原创文章 · 获赞 115 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/chen1415886044/article/details/101226980