在共享内存多处理器结构中,线程可用于实现并行性。
在理解线程之前,首先要了解unix进程。进程由操作系统创建,并且需要相当大的“开销”。进程包含有关程序资源和程序执行状态的信息,包括:
- 进程ID,进程组ID,用户ID和组ID
- 工作目录
- 程序指令
- 寄存器
- 栈
- 堆
- 文件描述符
- 信号动作
- 共享库
- 进程间通信工具(消息队列,管道,信号量或者共享内存)
线程使用并存在于这些进程资源中,但是能够由操作系统进行独立调度并且作为独立实体运行
线程
- 栈指针
- 寄存器
- 调度属性
- 线程数据
共享内存模型
- 所有线程都可以访问相同的全局变量
- 线程也有自己的私有数据
- 程序员负责同步访问全局共享数据
线程安全
线程安全性:简而言之,指的是应用程序同时执行多个线程而不”破坏”共享数据或创建“竞争”条件的能力
创建和终止线程
pthread_create(thread,attr,start_routine,arg)
pthread_exit(状态)
pthread_cancel(线程)
pthread_attr_init(attr)
pthread_attr_destroy(attr)
线程属性
默认情况下,使用某些属性创建一个线程。程序员可以通过线程属性对象更改其中一些属性
属性包括
- 分离或可连接状态
- 调度继承
- 调度策略
- 调度参数
- 堆栈大小
- 堆栈地址
- 堆栈防护(溢出)大小
堆栈管理
pthread_attr_getstacksize (attr, stacksize)
pthread_attr_setstacksize (attr, stacksize)
pthread_attr_getstackaddr (attr, stackaddr)
pthread_attr_setstackaddr (attr, stackaddr)
线程管理
pthread_join (threadid,status)
pthread_detach (threadid)
pthread_attr_setdetachstate (attr,detachstate)
pthread_attr_getdetachstate (attr,detachstate)
线程的链接于分离,体现在我们是否要知道这个线程的返回值和状态
一个线程在我们连接(join)它之前可能就已经终止了。结果是,当一个线程是可连接时,POSIX线程系统必须保持、维护某些信息:至少是该线程的ID和返回值(the returned value)。的确,正在等待连接该线程的线程是需要这些信息的。实际上,POSIX线程系统也可保持和可连接线程相关的其它资源信息,比如线程的栈。从POSIX的角度来看,这是完全合法的。事实上,pthread_join()保证回收与已连接线程的任何存储空间。
那当我的线程不返回任何有用的信息,并且我不必等待它的完成时,我该怎么办?仅仅为了清理的意图,无论如何还是得必须调用pthrad_join()吗?
幸运的是,不必这样做。Pthreads提供了一种机制告诉管理系统:我正在开启这个线程,但我对连接它并没有兴趣;一旦该线程结束,请为我执行清理动作。这个操作叫做分离一个线程。我们可以按照如下方法分离一个线程:
- 在线程的创建期间,采用detachstate线程属性
- 在任何线程处调用pthread_detach()函数
互斥变量
pthread_mutex_init (mutex,attr)
pthread_mutex_destroy (mutex)
pthread_mutexattr_init (attr)
pthread_mutexattr_destroy (attr)
pthread_mutex_lock (mutex)
pthread_mutex_trylock (mutex)
pthread_mutex_unlock (mutex)
条件变量
pthread_cond_init (condition,attr)
pthread_cond_destroy (condition)
pthread_condattr_init (attr)
pthread_condattr_destroy (attr)
pthread_cond_wait (condition,mutex)
pthread_cond_signal (condition)
pthread_cond_broadcast (condition)
例子代码
/******************************************************************************
* FILE: condvar.c
* DESCRIPTION:
* Example code for using Pthreads condition variables. The main thread
* creates three threads. Two of those threads increment a "count" variable,
* while the third thread watches the value of "count". When "count"
* reaches a predefined limit, the waiting thread is signaled by one of the
* incrementing threads. The waiting thread "awakens" and then modifies
* count. The program continues until the incrementing threads reach
* TCOUNT. The main program prints the final value of count.
* SOURCE: Adapted from example code in "Pthreads Programming", B. Nichols
* et al. O'Reilly and Associates.
* LAST REVISED: 03/07/17 Blaise Barney
******************************************************************************/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 3
#define TCOUNT 10
#define COUNT_LIMIT 12
int count = 0;
pthread_mutex_t count_mutex;
pthread_cond_t count_threshold_cv;
void *inc_count(void *t)
{
int i;
long my_id = (long)t;
for (i=0; i < TCOUNT; i++) {
pthread_mutex_lock(&count_mutex);
count++;
/*
Check the value of count and signal waiting thread when condition is
reached. Note that this occurs while mutex is locked.
*/
if (count == COUNT_LIMIT) {
printf("inc_count(): thread %ld, count = %d Threshold reached. ",
my_id, count);
pthread_cond_signal(&count_threshold_cv);
printf("Just sent signal.\n");
}
printf("inc_count(): thread %ld, count = %d, unlocking mutex\n",
my_id, count);
pthread_mutex_unlock(&count_mutex);
/* Do some work so threads can alternate on mutex lock */
sleep(1);
}
pthread_exit(NULL);
}
void *watch_count(void *t)
{
long my_id = (long)t;
printf("Starting watch_count(): thread %ld\n", my_id);
/*
Lock mutex and wait for signal. Note that the pthread_cond_wait routine
will automatically and atomically unlock mutex while it waits.
Also, note that if COUNT_LIMIT is reached before this routine is run by
the waiting thread, the loop will be skipped to prevent pthread_cond_wait
from never returning.
*/
pthread_mutex_lock(&count_mutex);
while (count < COUNT_LIMIT) {
printf("watch_count(): thread %ld Count= %d. Going into wait...\n", my_id,count);
pthread_cond_wait(&count_threshold_cv, &count_mutex);
printf("watch_count(): thread %ld Condition signal received. Count= %d\n", my_id,count);
}
printf("watch_count(): thread %ld Updating the value of count...\n", my_id);
count += 125;
printf("watch_count(): thread %ld count now = %d.\n", my_id, count);
printf("watch_count(): thread %ld Unlocking mutex.\n", my_id);
pthread_mutex_unlock(&count_mutex);
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
int i, rc;
long t1=1, t2=2, t3=3;
pthread_t threads[3];
pthread_attr_t attr;
/* Initialize mutex and condition variable objects */
pthread_mutex_init(&count_mutex, NULL);
pthread_cond_init (&count_threshold_cv, NULL);
/* For portability, explicitly create threads in a joinable state */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&threads[0], &attr, watch_count, (void *)t1);
pthread_create(&threads[1], &attr, inc_count, (void *)t2);
pthread_create(&threads[2], &attr, inc_count, (void *)t3);
/* Wait for all threads to complete */
for (i = 0; i < NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
printf ("Main(): Waited and joined with %d threads. Final value of count = %d. Done.\n",
NUM_THREADS, count);
/* Clean up and exit */
pthread_attr_destroy(&attr);
pthread_mutex_destroy(&count_mutex);
pthread_cond_destroy(&count_threshold_cv);
pthread_exit (NULL);
}
网友评论