1、线程概念
线程包含了表示进程内执行环境必须的信息,其中包括进程中标识线程的线程ID、一组寄存器值、栈、调度优先级和策略、信号屏蔽字、errno变量以及线程私有数据。进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本、程序的全局内存和堆内存、栈以及文件描述符。
2、线程标识
线程ID用pthread_t数据类型表示
必须使用函数对二个线程ID进行比较
#include <pthread.h>
int pthread_equal(pthread_t t1, pthread_t t2);
|
通过pthread_self获得自身线程ID
#include <pthread.h>
pthread_t pthread_self(void);
|
3、创建线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
|
当pthread_create成功返回时,由tidp指各的内存单元被设置为新创建线程的线程ID
attr参数用于定制各种不同的线程属性。
pthread 库不是 Linux 系统默认的库,连接时需要使用静态库 libpthread.a,所以在使用pthread_create()创建线程,以及调用 pthread_atfork()函数建立fork处理程序时,需要链接该库。
在编译中要加 -lpthread参数
gcc thread.c -o thread -lpthread |
create_thread.c
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
pthread_t ntid;
void printids(const char *s) {
pid_t pid;
pthread_t tid;
pid = getpid();
tid = pthread_self();
printf("%s pid %u tid %u (0x%x)\n",s,(unsigned int)pid,(unsigned int)tid,(unsigned int)tid);
}
void * thr_fn(void * arg) {
printids("new thread:");
return((void *)0);
}
int main(int argc, char **argv) {
int err;
err = pthread_create(&ntid,NULL,thr_fn,NULL);
if(err != 0) {
printf("pthread create error");
}
printids("main thread:");
sleep(1);
exit(0);
}
|
4、线程终止
如果进程中的任一线程调用了exit、_Exit或者_exit,那么整个进程就会终止。
如果信号的默认动作是终止进程,那么把信号发送到线程会终止整个进程。
线程退出方式
1)线程只是从启动例程中返回,返回值是线程的退出码
2)线程可以被同一进程中的其他线程取消。
3)线程调用pthread_exit
#include <pthread.h>
void pthread_exit(void *retval);
|
retval是一个无类型指针,与传给启动例程的单个参数类似。进程中的其他线程可以通过调用pthread_join访问到这个指针。
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
|
调用线程将一直被阻塞,直到指定的线程调用pthread_exit,从启动例程中返回或者被取消。
获取已终止的线程的退出码
thread_exit_code.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
void *thr_fn1(void *arg) {
printf("thread 1 returning\n");
return ((void*)1);
}
void *thr_fn2(void *arg) {
printf("thread 2 returning\n");
return ((void*)2);
}
int main(int argc, char **argv) {
int err;
pthread_t tid1,tid2;
void *tret;
err = pthread_create(&tid1,NULL,thr_fn1,NULL);
if(err != 0) {
printf("can`t create thread1 %s",strerror(err));
exit(0);
}
err = pthread_create(&tid2,NULL,thr_fn2,NULL);
if(err != 0) {
printf("can`t create thread1 %s",strerror(err));
exit(0);
}
err = pthread_join(tid1,&tret);
if(err != 0) {
printf("can`t join with thread 1 %s",strerror(err));
exit(0);
}
printf("thread 1 exit code %s\n",strerror(err));
err = pthread_join(tid2,&tret);
if(err != 0) {
printf("can`t join with thread 2 %s\n",strerror(err));
exit(0);
}
printf("thread 2 exit code %s\n",strerror(err));
exit(0);
}
|
线程可以通过调用pthread_cancel函数来请求取消同一进程中的其他线程。
#include <pthread.h>
int pthread_cancel(pthread_t thread);
|
5、线程同步
互斥变量用pthread_mutex_t数据类型表示,在使用互斥变量以前,必须首先对它进行初始化。
可以把它设置为常量PTHREAD_MUTEX_INITALIZER(只对静态分配的互斥量)
通过调用pthread_mutex_init函数进行初始化。
如果动态的分配互斥量(malloc),那么释放内存前需要调用pthread_mutex_destroy
#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
对互斥量进行加锁,需要调用pthread_mutex_lock,如果互斥量已经上锁,调用线程将阻塞直到互斥量被解锁。对互斥量解锁,需要调用
pthread_mutex_unlock
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
|
如果不希望被阻塞,它可以使用pthread_mutex_trylock尝试对互斥量进行加锁。
如果调用pthread_mutex_trylock时互斥量处于未锁住状态,那么将锁住互斥量,不会出现阻塞并返回0,否则失败
相关推荐
### UNIX高级编程知识点详解 #### 一、课程体系与学习目标概述 - **语言**: 本课程主要聚焦于两种主流的编程语言:C 和 C++。 - **算法**: 学习经典算法及其优化方法,提高解决复杂问题的能力。 - **数据结构**: ...
- **示例代码分析**:书中提供了大量的实际编程示例,覆盖各种UNIX编程场景,帮助读者理解和应用所学知识。 - **调试与故障排查**:教授如何使用调试工具和技巧,高效定位和解决编程过程中遇到的问题。 #### 5. ...
UNIX 网络编程读书笔记 ...本篇读书笔记涵盖了 UNIX 网络编程的基础知识、并发服务器设计思想、TCP/IP 协议、Socket 编程、高级知识点和网络服务器设计等多个方面,对于学习 UNIX 网络编程的读者非常有价值。
### APUE读书笔记《UNIX环境高级编程第二版》知识点概览 #### 第一章 Unix基础 **1. Unix手册页** - 手册页是Unix系统中查询命令、函数等帮助文档的方式。 - 分类包括命令(1)、系统调用(2)、库函数(3)、特殊...
在深入探讨多线程Unix编程之前,...学习笔记中的内容可能涵盖了以上各个知识点的实例、代码示例和解析,帮助你理解和实践多线程Unix编程。通过不断实践和学习,你将能够熟练地在Unix环境中编写高效的多线程应用程序。
- **Unix手册页**:介绍如何使用`man`命令查询Unix/Linux系统中的命令、函数等的文档,是学习Unix编程的重要资料来源。 - **系统调用与库函数**:系统调用是应用程序与操作系统内核之间的接口,库函数则是对系统调用...
它为开发者提供了丰富的命令行工具和强大的编程环境,其中C语言是UNIX系统的核心编程语言。 C语言在UNIX系统中的地位至关重要,因为UNIX最初的许多核心组件就是用C语言编写的。C语言具有简洁、高效、灵活的特点,...
【UNIX多线程学习笔记】 在UNIX操作系统中,多线程是一种重要的编程模型,它允许多个执行流在单个进程中并发运行。多线程带来了许多优势,包括提高应用程序响应速度,充分利用多CPU系统的资源,以及优化程序结构,...
这两者的编程接口有很高的相似性,因此学习Unix编程对理解Linux编程也非常有帮助。 本书可能包含以下内容: 1. **shell编程**:讲解Bash shell和其他Unix shell的基本语法,包括命令行参数、环境变量、重定向、...
8. **库函数与系统调用**:C语言是UNIX编程的主要语言,系统调用(如上述的`open()`、`write()`等)是直接与内核交互的接口,而库函数(如`stdio.h`中的`printf()`)则提供更友好的编程体验。 9. **网络编程**:...
《高级Linux环境编程》或称为APUE(Advanced Programming in the UNIX ...这本书不仅涵盖了UNIX编程的核心概念,还包括了许多实用的编程技巧和解决方案,是一本非常适合在Linux环境下从事系统编程学习的参考书籍。
"精通UNIX下C语言编程与项目实践+源代码+笔记.zip" 是一个包含详细学习材料的压缩文件,它包括了书籍、源代码以及笔记。这将帮助学习者不仅了解理论知识,还能通过实际的项目练习来加深理解。标签揭示了其主要内容:...
在深入探讨UNIX网络编程时,我们关注的核心是TCP/IP连接的生命周期,特别是涉及套接字关闭的细节。在TCP连接的生命周期中,关闭连接通常涉及四个阶段,这被称为"四次挥手"(Four-Way Handshake)过程。下面将详细...
多线程学习笔记 iOS开发中,多线程是一种常见的技术手段,用于优化应用程序的性能,提升用户体验。多线程的核心是让程序能够并发地执行多个任务,合理地利用设备的计算能力,尤其是在拥有多个核心的处理器上。 ...
UNIX编程主要涉及系统调用,如进程控制、文件I/O、网络通信等。通过学习`fork`、`exec`、`pipe`、`socket`等函数,开发者可以创建多进程、多线程的程序,并进行进程间通信。Windows编程则涉及到API函数,如...
### Linux与Unix Shell编程之内核同步技术详解 #### 一、引言 在Linux操作系统中,内核作为操作系统的核心部分,负责管理系统的资源以及协调各个应用程序之间的交互。随着多核处理器的普及,如何有效地管理和同步...