POSIX多线程编程(上)-基本概念
线程概念
我们把正在计算机中执行的程序叫做"进程"(Process) ,而不将其称为程序(Program)。所谓"线程"(Thread),是"进程"中某个单一顺序的控制流。线程是进程中的实体,一个进程可以拥有多个线程,一个线程必须有一个父进程。线程不拥有系统资源,只有运行必须的一些数据结构;它与父进程的其它线程共享该进程所拥有的全部资源。
在多中央处理器的系统里,不同线程可以同时在不同的中央处理器上运行,甚至当它们属于同一个进程时也是如此。大多数支持多处理器的操作系统都提供编程接口来让进程可以控制自己的线程与各处理器之间的关联度(affinity)。
有时候,线程也称作轻量级进程。就象进程一样,线程在程序中是独立的、并发的执行路径,每个线程有它自己的堆栈、自己的程序计数器和自己的局部变量。但是,与分隔的进程相比,进程中的线程之间的隔离程度要小。它们共享内存、文件句柄和其它每个进程应有的状态。
线程标识
类似于每一个进程都有唯一的进程ID(pid_t)标识,每一个线程也有对应的线程ID(pthread_t)标识。不同之处在于进程ID在整个系统中是唯一的而线程ID仅在它所属的进程环境中有效。与线程标识操作有关的函数接口如下:
#include <pthread.h>
int pthread_equal(pthread_t t1, pthread_t t2); // compare thread IDs
pthread_t pthread_self(void); // obtain ID of the calling thread
线程的创建、终止、取消
线程创建、终止
线程的创建可以通过调用pthread_create()
接口创建,线程会采用以下四种方式终止:
It calls
pthread_exit()
, specifying an exit status value that is available to another thread in the same process that callspthread_join()
.It returns from start_routine(). This is equivalent to calling
pthread_exit()
with the value supplied in the return statement.It is canceled (see
pthread_cancel()
).Any of the threads in the process calls exit(), or the main thread performs a return from
main()
. This causes the termination of all threads in the process.
函数原型:
#include <pthread.h>
/**
The attr argument points to a pthread_attr_t structure whose contents are used at thread creation time to determine attributes for the new thread; this structure is
initialized using pthread_attr_init(3) and related functions. If attr is NULL, then the thread is created with default attributes.
RETURN VALUE
On success, pthread_create() returns 0; on error, it returns an error number, and the contents of *thread are undefined.
*/
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
void pthread_exit(void *retval);
下面一段代码是linux函数手册一个demo很好的展示了线程的创建、终止、等待:
EXAMPLE
The program below demonstrates the use of pthread_create(), as well as a number of other functions in the pthreads API.In the following run, on a system providing the NPTL threading implementation, the stack size defaults to the value given by the "stack size" resource limit:
$ ulimit -s
8192 # The stack size limit is 8 MB (0x80000 bytes)
$ ./a.out hola salut servus
Thread 1: top of stack near 0xb7dd03b8; argv_string=hola
Thread 2: top of stack near 0xb75cf3b8; argv_string=salut
Thread 3: top of stack near 0xb6dce3b8; argv_string=servus
Joined with thread 1; returned value was HOLA
Joined with thread 2; returned value was SALUT
Joined with thread 3; returned value was SERVUS
In the next run, the program explicitly sets a stack size of 1MB (using pthread_attr_setstacksize(3)) for the created threads:
$ ./a.out -s 0x100000 hola salut servus
Thread 1: top of stack near 0xb7d723b8; argv_string=hola
Thread 2: top of stack near 0xb7c713b8; argv_string=salut
Thread 3: top of stack near 0xb7b703b8; argv_string=servus
Joined with thread 1; returned value was HOLA
Joined with thread 2; returned value was SALUT
Joined with thread 3; returned value was SERVUS
Program source
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h> #define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0) #define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0) struct thread_info { /* Used as argument to thread_start() */
pthread_t thread_id; /* ID returned by pthread_create() */
int thread_num; /* Application-defined thread # */
char *argv_string; /* From command-line argument */
}; /* Thread start function: display address near top of our stack,
and return upper-cased copy of argv_string */ static void *
thread_start(void *arg)
{
struct thread_info *tinfo = (struct thread_info *) arg;
char *uargv, *p; printf("Thread %d: top of stack near %p; argv_string=%s\n",
tinfo->thread_num, &p, tinfo->argv_string); uargv = strdup(tinfo->argv_string);
if (uargv == NULL)
handle_error("strdup"); for (p = uargv; *p != '\0'; p++)
*p = toupper(*p); return uargv;
} int
main(int argc, char *argv[])
{
int s, tnum, opt, num_threads;
struct thread_info *tinfo;
pthread_attr_t attr;
int stack_size;
void *res; /* The "-s" option specifies a stack size for our threads */ stack_size = -1;
while ((opt = getopt(argc, argv, "s:")) != -1) {
switch (opt) {
case 's':
stack_size = strtoul(optarg, NULL, 0);
break; default:
fprintf(stderr, "Usage: %s [-s stack-size] arg...\n",
argv[0]);
exit(EXIT_FAILURE);
}
} num_threads = argc - optind; /* Initialize thread creation attributes */ s = pthread_attr_init(&attr);
if (s != 0)
handle_error_en(s, "pthread_attr_init"); if (stack_size > 0) {
s = pthread_attr_setstacksize(&attr, stack_size);
if (s != 0)
handle_error_en(s, "pthread_attr_setstacksize");
} /* Allocate memory for pthread_create() arguments */ tinfo = calloc(num_threads, sizeof(struct thread_info));
if (tinfo == NULL)
handle_error("calloc"); /* Create one thread for each command-line argument */ for (tnum = 0; tnum < num_threads; tnum++) {
tinfo[tnum].thread_num = tnum + 1;
tinfo[tnum].argv_string = argv[optind + tnum]; /* The pthread_create() call stores the thread ID into
corresponding element of tinfo[] */ s = pthread_create(&tinfo[tnum].thread_id, &attr,
&thread_start, &tinfo[tnum]);
if (s != 0)
handle_error_en(s, "pthread_create");
} /* Destroy the thread attributes object, since it is no
longer needed */ s = pthread_attr_destroy(&attr);
if (s != 0)
handle_error_en(s, "pthread_attr_destroy"); /* Now join with each thread, and display its returned value */ for (tnum = 0; tnum < num_threads; tnum++) {
s = pthread_join(tinfo[tnum].thread_id, &res);
if (s != 0)
handle_error_en(s, "pthread_join"); printf("Joined with thread %d; returned value was %s\n",
tinfo[tnum].thread_num, (char *) res);
free(res); /* Free memory allocated by thread */
} free(tinfo);
exit(EXIT_SUCCESS);
}
关于以上demo部分代码有几个地方需要说明:
线程等待接口pthread_join()
,可以等待指定的线程,并且获取等待进程的返回消息(包括pthread_exit()
返回码、return 返回、线程被取消时的PTHREAD_CANCEL)。pthread_join()
是阻塞等待的,在等待的线程返回前此函数处于阻塞状态,另外线程如果处于脱离状态函数会调用失败,返回EINVAL。
线程的属性及接口,下面章节讲会描述。
pthread_join函数原型:
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
线程取消
线程可以通过调用pthread_cancel()
来取消同一进程下的其他线程。线程取消仅仅是向被取消线程提出了个请求,被取消线程实际上会继续执行,根据自身取消方式来选择线程取消时机,有可能是立即取消,也有可能达到下个取消点才真正取消线程。线程取消会返回PTHREAD_CANCLE状态。
#include <pthread.h>
int pthread_cancel(pthread_t thread);
RETURN VALUE
On success, pthread_cancel() returns 0; on error, it returns a non-zero error number.
POSIX多线程编程(上)-基本概念的更多相关文章
- POSIX 多线程编程及理解
最近开发基于ZYNQ的嵌入式linux程序,涉及到多线程使用,将一些内容整理如下: POSIX多线程编程最为基础和重要的可以分为两部分: 线程操作-Thread Management 线程同步-Syn ...
- [posix]Posix多线程编程
就不排版了,可以到原作者博客下看 转自:http://www.cnblogs.com/zhangsf/archive/2013/09/09/3309867.html 目录表 摘要 译者序 Pthre ...
- Win32多线程编程(1) — 基础概念篇
内核对象的基本概念 Windows系统是非开源的,它提供给我们的接口是用户模式的,即User-Mode API.当我们调用某个API时,需要从用户模式切换到内核模式的I/O System Serv ...
- java多线程编程01---------基本概念
一. java多线程编程基本概念--------基本概念 java多线程可以说是java基础中相对较难的部分,尤其是对于小白,次一系列文章的将会对多线程编程及其原理进行介绍,希望对正在多线程中碰壁的小 ...
- Posix多线程编程学习笔记
Blaise Barney, Lawrence Livermore National Laboratory )标准制订了这一标准接口.依赖于该标准的实现就称为POSIX threads 或者Pthre ...
- POSIX多线程编程-条件变量pthread_cond_t
条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用.使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化.一旦其它 ...
- [转]Linux 的多线程编程的高效开发经验
Linux 平台上的多线程程序开发相对应其他平台(比如 Windows)的多线程 API 有一些细微和隐晦的差别.不注意这些 Linux 上的一些开发陷阱,常常会导致程序问题不穷,死锁不断.本文中我们 ...
- Linux多线程编程(不限Linux)【转】
——本文一个例子展开,介绍Linux下面线程的操作.多线程的同步和互斥. 前言 线程?为什么有了进程还需要线程呢,他们有什么区别?使用线程有什么优势呢?还有多线程编程的一些细节问题,如线程之间怎样同步 ...
- Linux 的多线程编程的高效开发经验(转)
http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/ 背景 Linux 平台上的多线程程序开发相对应其他平台(比如 Windows)的多 ...
随机推荐
- 关于Arrays类总结
Arrays是java中的工具类,其中所有的方法都是static.类名就可以直接调用其中的方法. 本文部分引用自: http://www.importnew.com/8952.html Arrays. ...
- 面试学到的css布局,细节影响了我的面试成绩
这几天的面试很纠结,也让我注意到我的前端知识确实不行,从两个小细节总结: 1:body体的居中样式. 这个在IE和非IE Firefox Chrome Opera下面的差别 IE下text-align ...
- Centos 6.4 安装elasticsearch+kibana
elasticsearch和kibanna的链接地址:https://www.elastic.co/downloads,我的环境里用的包为kibana-4.1.1-linux-x64.tar.gz和e ...
- oracle两种导出导入方式,即imp与impdp之比较
尽管使用了很多次impexp及impdpexpdp但是使用起来还是会遇到很多问题,现总结如下: 应用:将一个用户的所有表结构及索引,触发器,过程,函数等导入到另一用户里 imp/exp 导出用户表结构 ...
- Java中startWith方法的使用!
今天看Java代码时,看到了字符串有一个方法是startsWith(String str)当时觉得见名之意,很简单吗,然后就自己动手做了一下,没想到发现了一个startsWith()方法的重载,sta ...
- Visual Studio.NET、asp.net和C#间的关系是怎样的?
asp.net是一种技术,要实现这种技术,就得有底层的实现技术编程语言,这个语言就是C#,(只是绝大多数首选C#),要想用C#实现asp.net技术,就得有编程的工具软件,这个软件我一直用visual ...
- spark下统计单词频次
写了一个简单的语句,还没有优化: scala> sc. | textFile("/etc/profile"). | flatMap((s:String)=>s.spli ...
- asp生成静态HTML(动态读取)
这样的代码多用于我们没有实现设计生成静态的功能,但又想临时将一些动态页面生成静态的,直接获取动态内容并保存为静态的 复制代码代码如下: <!--#include file="admin ...
- Cordova+angularjs+ionic+vs2015开发(二)
欢迎加群学习:457351423 这里有4000多部学习视频,涵盖各种技术,有需要的欢迎进群学习! 一.创建空白Cordova应用 打开VS,选择[新建项目],选择其它语言JavaScript或者Ty ...
- DropdownListFor无法正确绑定值-同名问题
DropdownListFor无法正确绑定值 如果以下面的方式进行绑定: <%: Html.DropDownListFor(model => model.subType, ViewBag ...