`

linux c学习笔记----线程创建与终止

阅读更多



进程原语 线程原语 描述
fork pthread_create 创建新的控制流
exit pthread_exit 从现有的控制流中退出
waitpid pthread_join 从控制流中得到退出状态
atexit pthread_cancel_push 注册在退出控制流时调用的函数
getpid pthread_self 获取控制流的ID
abort pthread_cancel 请深圳市控制流的非正常退出



pthread_create

int pthread_create(pthread_t *thread, pthread_addr_t *arr,void* (*start_routine)(void *), void *arg);

  •  thread   :用于返回创建的线程的ID
  • arr       : 用于指定的被创建的线程的属性,上面的函数中使用NULL,表示使用默认的属性
  • start_routine   : 这是一个函数指针,指向线程被创建后要调用的函数
  • arg      : 用于给线程传递参数,在本例中没有传递参数,所以使用了NULL

线程创建时并不能保证哪个线程会先运行:是新创建的线程还是调用线程。新创建的线程可以访问进程的地址空间,
并且继承调用线程的浮点环境和信号屏蔽字,但是该线程的未决信号集被消除。

单个线程可以通过三种方式退出,在不终止整个进程的情况下停止它的控制流。
(1)线程只是从启动全程中返回,返回值是线程的退出码。
(2)线程可以被同一进程中的其他线程取消
(3)线程调用pthread_exit


void pthread_exit(void *rval_ptr)
rval_ptr是一个无类型指针,与传给启动例程的单个参数类似。进程中的其他线程可以通过调用pthread_join函数访问到这个指针。

int pthread_join(pthread_t thread,void **rval_ptr);
成功返回0,失败返回错误编号
调用线程将一直阻塞,直到指定的线程调用pthread_exit,从启动例程中返回或者被取消。
如果线程只是从它的启动例程返回,rval_ptr将包含返回码。如果线程被取消,由rval_ptr指定的内存单元被置为PTHREAH_CANCELED.
可以通过调用pthread_join自动把线程置于分离状态,这样资源就可以恢复。如果线程已经处于分离状态,pthread_join调用就会失败,返回EINVAL.
如果对线程的返回值并不感兴趣,可以把rval_ptr置为NULL。在这种情况下,调用pthread_join函数将等待指定的线程停止,但并不获取线程的终止状态。

在调用线程的栈上分配了该结构,那么其他的线程在使用这个结构进内存可能已经改变了。又如,线程在自己的栈上分配了一个结构然后把指向这个结构的指针传给pthread_exit,那么当调用pthread_join的线程试图使用该结构时,这个栈有可能已经被撤消,这块内存也已另作他用。
例如:#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>

struct foo {
	int a, b, c, d;
};

void printfoo(const char *s, const struct foo *fp)
{
	printf("%s",s);
	printf("  structure at 0x%x\n", (unsigned)fp);
	printf("  foo.a = %d\n", fp->a);
	printf("  foo.b = %d\n", fp->b);
	printf("  foo.c = %d\n", fp->c);
	printf("  foo.d = %d\n", fp->d);
}

void *thr_fn1(void *arg)
{
	struct foo	foo = {1, 2, 3, 4};

	printfoo("thread 1:\n", &foo);
	pthread_exit((void *)&foo);
}

void *thr_fn2(void *arg)
{
	struct foo	fao = { 2,2, 3, 4};
	printf("thread 2: ID is %d\n", (unsigned int)pthread_self());
	pthread_exit((void *)0);
}

int main(void)
{
	int			err;
	pthread_t	tid1, tid2;
	struct foo	*fp;

	err = pthread_create(&tid1, NULL, thr_fn1, NULL);
	if (err != 0)
		printf("can't create thread 1: %d\n", strerror(err));
	err = pthread_join(tid1, (void *)&fp);
	if (err != 0)
		printf("can't join with thread 1: %d\n", strerror(err));
	sleep(1);
	printf("parent starting second thread\n");
	err = pthread_create(&tid2, NULL, thr_fn2, NULL);
	if (err != 0)
		printf("can't create thread 2: %d\n", strerror(err));
	sleep(1);
	printfoo("parent:\n", fp);
	exit(0);
}

 


void pthread_cleanup_push(void (*rtn)(void *),void *arg);
void pthread_cleanup_pop(int execute);
当线程执行以下动作时调用清理函数,调用参数为arg,清理函数rtn的调用顺序是由pthread_cleanup_push函数来安排的。
1.调用pthread_exit时。2.响应取消请求时。3.用非零execute参数调用pthread_cleanup_pop时。
如果execute参数置为0,清理函数将不被调用。无论哪种情况,pthread_cleanup_pop都将删除上次pthread_clean_push调用建立的清理处理程序。
实例:
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>

void cleanup(void *arg)
{
	printf("cleanup: %s\n", (char *)arg);
}

void *thr_fn1(void *arg)
{
	printf("thread 1 start\n");
	pthread_cleanup_push(cleanup, "thread 1 first handler");
	pthread_cleanup_push(cleanup, "thread 1 second handler");
	printf("thread 1 push complete\n");
	if (arg)
		return((void *)1);
		// pthread_exit((void *)2);
		
	pthread_cleanup_pop(0);
	pthread_cleanup_pop(0);
	// return((void *)1);
	pthread_exit((void *)2);

}

void *thr_fn2(void *arg)
{
	printf("thread 2 start\n");
	pthread_cleanup_push(cleanup, "thread 2 first handler");
	pthread_cleanup_push(cleanup, "thread 2 second handler");
	printf("thread 2 push complete\n");
	if (arg)
		pthread_exit((void *)2);
	pthread_cleanup_pop(0);
	pthread_cleanup_pop(0);
	pthread_exit((void *)2);
}

int main(void)
{
	int			err;
	pthread_t	tid1, tid2;
	void		*tret;

	err = pthread_create(&tid1, NULL, thr_fn1, (void *)1);
	if (err != 0)
		printf("can't create thread 1: %c\n", strerror(err));
	err = pthread_create(&tid2, NULL, thr_fn2, (void *)1);
	if (err != 0)
		printf("can't create thread 2: %c\n", strerror(err));
	err = pthread_join(tid1, &tret);
	if (err != 0)
		printf("can't join with thread 1: %c\n", strerror(err));
	printf("thread 1 exit code %d\n", (int)tret);
	err = pthread_join(tid2, &tret);
	if (err != 0)
		printf("can't join with thread 2: %c\n", strerror(err));
	printf("thread 2 exit code %d\n", (int)tret);
	exit(0);
}
 

 

分享到:
评论

相关推荐

    linux编程学习笔记PDF资料下载.txt

    根据提供的文件信息,我们可以推断出这是一份关于Linux编程学习笔记的PDF资料。下面将对这份资料可能涉及的关键知识点进行详细的阐述。 ### Linux编程基础知识 #### 1. Linux操作系统概述 - **定义与特点**:Linux...

    Linux 进程 线程学习笔记

    ### Linux进程与线程创建详解 #### 进程与线程的概念 在深入探讨Linux下C语言编程中进程和线程的创建之前,我们先来理解一下进程与线程的基本概念。 - **进程**:是操作系统进行资源分配和调度的基本单位,每个...

    linux系统编程笔记

    Linux系统编程笔记涉及到的内容广泛,涵盖了从基础的出错处理到进程管理,从内存管理到进程间通信,以及守护进程设计等多个层面的知识。下面详细说明各个部分的知识点: 1. 常见出错处理 - abort函数用于异常终止...

    Linux系统编程学习笔记

    ### Linux系统编程学习笔记 #### 一、IO **1.1 标准I/O (stdio)** - **fopen/fclose**: `fopen` 用于打开或创建一个文件,并返回一个指向该文件的 `FILE *` 类型的指针。`fclose` 用于关闭由 `FILE *` 指向的文件...

    C语言学习笔记

    C语言学习笔记中所涉及的知识点非常丰富,涵盖了C语言的基础知识、高级特性、系统级编程以及常用开发工具等。 一、基础部分知识点 1. 数据类型:C语言的基本数据类型包括整型(如char、short、int、long、longlong...

    linux-kernel-boot-thread.zip_kernel thread

    这篇学习笔记深入探讨了这个主题,旨在帮助读者理解Linux内核启动线程的工作原理、创建方法以及其在系统中的作用。 首先,内核启动线程是内核自身启动的第一个线程,它的主要职责是初始化系统资源,如内存管理、...

    linux学习笔记:进程

    学习Linux的进程管理对于理解和操作系统的运行至关重要。本篇笔记主要探讨了以下几个方面的知识点: 1. **进程状态**: - **可运行态(TASK_RUNNING)**:进程正在CPU上执行或等待执行。 - **可中断的等待(TASK_...

    UNIX多线程学习笔记

    【UNIX多线程学习笔记】 在UNIX操作系统中,多线程是一种重要的编程模型,它允许多个执行流在单个进程中并发运行。多线程带来了许多优势,包括提高应用程序响应速度,充分利用多CPU系统的资源,以及优化程序结构,...

    Linux学习文档_多线程编程

    在"Linux学习文档_多线程编程"中,我们可以预期包含以下几个关键知识点: 1. **线程创建**:在Linux中,我们通常使用`pthread_create()`函数来创建新线程。这个函数需要传递线程函数的指针、线程参数、线程属性以及...

    C 学习笔记1

    【C语言学习笔记1】 本笔记主要涵盖了C语言的基础、高级特性和系统层面的知识,以及相关的开发工具。以下是对各个部分的详细说明: **第一部分:语言基础** 1. **数据类型** - `char`:8位有符号整数。 - `...

    Linux 初级学习的基本概念和资料

    提供的压缩包文件包含一系列关于Linux系统编程的学习笔记,如线程、信号、文件I/O、进程管理、内存管理、进程间通信等主题,这些都是Linux初级学习的关键点。通过阅读这些笔记,可以深入理解Linux底层机制,为后续的...

    linux应用程序开发,读书笔记

    ### Linux应用程序开发基础知识点 #### 一、Linux操作系统概述 **Linux** 是一款免费且开源的类Unix操作系统,...通过上述知识点的学习,开发者能够更好地理解和使用Linux系统,为后续的应用程序开发打下坚实的基础。

    Linux网络编程笔记(修订版)

    ### Linux网络编程笔记(修订版) #### 基本概念 网络编程是在计算机网络中实现数据交换和资源共享的重要技术手段。对于Linux环境下的网络编程,理解基础概念是至关重要的第一步。 1. **OSI参考模型**:开放系统...

    UniGui 学习笔记.pdf

    从提供的学习笔记内容来看,UniGUI具备了创建现代Web应用程序所需的关键特性,包括跨平台、状态管理、会话控制以及与客户端的紧密集成。开发者在使用UniGUI时,需对这些概念有清晰的理解,才能有效利用其提供的功能...

    Linux系统和网络编程学习文件

    - **Markdown语法**:可能的文档格式,用于编写清晰易读的学习笔记。 这个"linux-learning-master"文件名可能指示这是一个开源项目的仓库,可能包含了源代码、文档、教程等资源,通过学习这些内容,你可以逐步提升...

Global site tag (gtag.js) - Google Analytics