线程概念

  我们把正在计算机中执行的程序叫做"进程"(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 calls pthread_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多线程编程(上)-基本概念的更多相关文章

  1. POSIX 多线程编程及理解

    最近开发基于ZYNQ的嵌入式linux程序,涉及到多线程使用,将一些内容整理如下: POSIX多线程编程最为基础和重要的可以分为两部分: 线程操作-Thread Management 线程同步-Syn ...

  2. [posix]Posix多线程编程

    就不排版了,可以到原作者博客下看 转自:http://www.cnblogs.com/zhangsf/archive/2013/09/09/3309867.html 目录表  摘要 译者序 Pthre ...

  3. Win32多线程编程(1) — 基础概念篇

      内核对象的基本概念 Windows系统是非开源的,它提供给我们的接口是用户模式的,即User-Mode API.当我们调用某个API时,需要从用户模式切换到内核模式的I/O System Serv ...

  4. java多线程编程01---------基本概念

    一. java多线程编程基本概念--------基本概念 java多线程可以说是java基础中相对较难的部分,尤其是对于小白,次一系列文章的将会对多线程编程及其原理进行介绍,希望对正在多线程中碰壁的小 ...

  5. Posix多线程编程学习笔记

    Blaise Barney, Lawrence Livermore National Laboratory )标准制订了这一标准接口.依赖于该标准的实现就称为POSIX threads 或者Pthre ...

  6. POSIX多线程编程-条件变量pthread_cond_t

    条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用.使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化.一旦其它 ...

  7. [转]Linux 的多线程编程的高效开发经验

    Linux 平台上的多线程程序开发相对应其他平台(比如 Windows)的多线程 API 有一些细微和隐晦的差别.不注意这些 Linux 上的一些开发陷阱,常常会导致程序问题不穷,死锁不断.本文中我们 ...

  8. Linux多线程编程(不限Linux)【转】

    ——本文一个例子展开,介绍Linux下面线程的操作.多线程的同步和互斥. 前言 线程?为什么有了进程还需要线程呢,他们有什么区别?使用线程有什么优势呢?还有多线程编程的一些细节问题,如线程之间怎样同步 ...

  9. Linux 的多线程编程的高效开发经验(转)

    http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/ 背景 Linux 平台上的多线程程序开发相对应其他平台(比如 Windows)的多 ...

随机推荐

  1. 命令行界面下用户和组管理之groupmod的使用

    NAME    groupmod - modify a group definition on the system SYNOPSIS       groupmod [options] GROUP O ...

  2. Callable、Future和FutureTask使用说明

    普通的创建线程,一种是直接继承Thread,另外一种就是实现Runnable接口.但是这两种都无法在执行完任务之后获取执行结果,Callable.Future就提供了这样的便利.   Future的方 ...

  3. 你了解C语言中的关键字volatile吗?

    我们在学习C语言的32个关键字时,大家都不太注意volatile这个关键字,volatile是一个类型修饰符.volatile的中文意思是“易变的”.那么在程序中我们在什么情况下才使用他呢?我们在分析 ...

  4. hdu 1095 A+B for Input-Output Practice (VII)

    A+B for Input-Output Practice (VII) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32 ...

  5. 在centos中php 在连接mysql的时候,出现Can't connect to MySQL server on 'XXX' (13)

    原文连接:http://hi.baidu.com/zwfec/item/64ef5ed9bf1cb3feca0c397c 红色的是命令 SQLSTATE[HY000] [2003] Can't con ...

  6. 在ef下使用lambda实现left join

    db.Categories .GroupJoin( db.Products, Category => Category.CategoryId, Product => Product.Cat ...

  7. string和stringbuilder

    1)String是一个引用类型,一旦字符串被创建,就不能修改 例如: String a="AAA"; String b=a; a与b值相同,但不是同一个对象: 每次使用 Syste ...

  8. 电脑中java环境的搭建

  9. HTML Music Entities/音乐符号

    HTML Music Entities Musical symbols Description Character(click) HTML-Entity Code-Decimal Code-Hex Q ...

  10. indeed 第二次笔试题

    1. Maximal Values 很简单,从前往后扫,找满足的,O(n),很容易就过掉了. maxn = 100. 没啥难点. 2. Bi-gram 用map统计个数,从前往后扫,每2个字符作为一个 ...