POSIX线程
(POSIX threads),简称Pthreads,是线程的POSIX标准。该标准定义了创建和操纵线程的一整套API。在类Unix操作系统(Unix、Linux、Mac OS X等)中,都使用Pthreads作为操作系统的线程.(来源百度百科)
POSIX线程提供了一个用于创建线程的基于C的接口。
使用pthread
之前,我们需要引用其对应的库头文件#import
常用函数说明
关于完整相关pthread
API,可参考Apple文档
-
pthread_create(thread,attr,start_routine,arg)
pthread_create创建一个新线程并使其可执行。可以在代码中的任何位置任意调用此例程。
pthread_create参数:
thread:线程对象,传递地址。
attr:可用于设置线程属性的对象。您可以指定线程属性对象,或者为默认值指定NULL
。
start_routine:线程创建后将执行的C函数地址。
arg:可以传递给start_routine的单个参数 。它必须通过引用传递为void类型的指针转换。如果不传递参数,则可以使用NULL
。 -
pthread_exit(void * _Nullable)
终止线程,无论工作是否完成,允许指定一个可选的终止状态参数。此可选参数通常返回到
连接
已终止线程的线程。
正常执行完成的子程序中,通常可以省去调用pthread_exit()
,除非想要传回可选的状态代码 -
pthread_cancel(pthread_t _Nonnull)
取消一个线程
-
pthread_attr_init(attr)
初始化属性对象
-
pthread_attr_destroy(attr)
销毁属性对象
-
pthread_join (pthread_t _Nonnull,status)
加入一个线程,是线程之间同步的一种方法
-
pthread_detach (threadid)
分离线程,可以用来明确分离线程,即使是可连接状态
-
pthread_attr_setdetachstate (attr,detachstate)
设置分离状态
-
pthread_attr_getdetachstate (attr,detachstate)
得到分离状态
-
pthread_self()
返回调用线程的系统分配的唯一线程ID
-
pthread_equal(thread[0], thread[1])
比较两个线程ID,如果两个ID不同,返回0,否则返回非零值。
-
pthread_once(pthread_once_t * _Nonnull, void (* _Nonnull)(void))
这个在进程中只执行一次。类似GCD里面的
dispatch_once
-
pthread_attr_getstacksize(attr,stacksize)
获取线程堆栈大小
-
pthread_attr_setstacksize(attr,stacksize)
设置线程堆栈大小
-
pthread_attr_getstackaddr(attr,stackaddr)
获取线程堆栈地址
pthread_attr_setstackaddr(attr,stackaddr)
设置线程堆栈地址
pthread线程简单创建与参数传递
将参数传递给线程
- pthread_create() 通参数传递给线程启动线程。对于必须传递多个参数的情况,通过创建包含所有参数的结构体,然后在pthread_create()函数中将指针传递给该结构,可以轻松克服此限制
- 所有参数必须通过引用传递并转换为
(void *)
单一参数传递实例:
- (IBAction)creatPthread:(id)sender {
pthread_t threads[2];
for (NSInteger i = 0; i<2; i++) {
pthread_create(&threads[i], NULL, studyPthreadMethond, (void *)i);
}
}
void *studyPthreadMethond(void *threadID)
{
long tid = (long)threadID;
NSLog(@"currentThread = %@ threadID%ld",[NSThread currentThread],tid);
pthread_exit(NULL);
return NULL;
}
//输出结果
currentThread = {number = 3, name = (null)} threadID0
currentThread = {number = 4, name = (null)} threadID1
如果要传递多个参数过去,可以传递结构体过去
struct thread_TestData{
int thread_id;
char *message;
};
struct thread_TestData thread_Test;
- (IBAction)creatPthread:(id)sender {
pthread_t thread;
thread_Test.message = "t";
thread_Test.thread_id = 1;
//如果thread_Test在此申明不是全局变量,会发现异步线程studyPthreadMethond里面接收不到正确的数据
//struct thread_TestData thread_Test;
pthread_create(&thread, NULL, studyPthreadMethond,(void *)&thread_Test);
}
void *studyPthreadMethond(void *threadData)
{
struct thread_TestData *getData;
getData = (struct thread_TestData *)threadData;
NSLog(@"test %p", getData);
int threadID = getData->thread_id;
char *msg = getData->message;
NSLog(@"threadID = %d message=%s %p",threadID,msg,getData->message);
pthread_exit(NULL);
return NULL;
}
pthread 线程加入与分离
线程加入是完成线程之间同步的一种方法。
如果线程需要加入,请考虑将其明确创建为可连接。
因为并非所有实现都可以默认将线程创建为可连接。
如果线程永远不需要与另一个线程连接,可考虑在分离状态下创建它。可以释放一些系统资源。
要将线程显示创建为可加入可连接或已分离状态,需要以下几步:
- 先声明
pthread_attr_t
属性变量 - 使用
pthread_attr_init()
初始化属性变量 -
pthread_attr_setdetachstate (attr,detachstate)
设置分离状态 - 完成后,使用
pthread_attr_destroy(attr)
销毁属性变量
使用实例:
- (IBAction)joinPthread:(id)sender {
pthread_t thread[5];
pthread_attr_t attr;
int pthreadCode;
void *status;
//初始化状态
pthread_attr_init(&attr);
//设置分离状态
int detachstate = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
int getdetachstate = pthread_attr_getdetachstate(&attr, &detachstate);
NSLog(@"getdetachstate = %d",getdetachstate);
for (NSInteger i = 0; i<5; i++) {
NSLog(@"MainThread:creating thread %ld\n",i);
pthreadCode = pthread_create(&thread[i], &attr, testPthreadA, (void *)i);
if (pthreadCode) {
NSLog(@"retrun error code form pthread_create is %d",pthreadCode);
exit(-1);
}
}
//销毁属性对象
pthread_attr_destroy(&attr);
for (NSInteger i = 0; i<5; i++) {
pthreadCode = pthread_join(thread[i], &status);
if (pthreadCode) {
NSLog(@"retrun error code form pthread_join is %d",pthreadCode);
exit(-1);
}
NSLog(@"completed join with thread %ld having a status of %ld\n",i,(long)status);
}
NSLog(@"compelted.Exiting\n");
//pthread_exit(NULL);这里调用退出会导致主线程退出
}
void *testPthreadA(void *t) {
double result = 0;
long pthreadID = (long)t;
NSLog(@"Thread %ld staring..\n",pthreadID);
for (NSInteger i = 0; i<100000; i++) {
result = result + i*i;
}
NSLog(@"Thread %ld end.Result=%lf",pthreadID,result);
//这里返回的状态就是status状态捕获的值
pthread_exit((void *)t);
}
打印结果如下:
getdetachstate = 0
MainThread:creating thread 0
MainThread:creating thread 1
Thread 0 staring..
MainThread:creating thread 2
MainThread:creating thread 3
Thread 1 staring..
Thread 0 end.Result=333328333350000.000000
Thread 2 staring..
MainThread:creating thread 4
Thread 3 staring..
Thread 1 end.Result=333328333350000.000000
Thread 2 end.Result=333328333350000.000000
completed join with thread 0 having a status of 0
Thread 4 staring..
completed join with thread 1 having a status of 1
Thread 3 end.Result=333328333350000.000000
completed join with thread 2 having a status of 2
Thread 4 end.Result=333328333350000.000000
completed join with thread 3 having a status of 3
completed join with thread 4 having a status of 4
compelted.Exiting
pthread 创建和销毁互斥锁
pthread
中的互斥锁的基本概念:在任何给定时间只有一个线程可以锁定(或拥有)互斥变量。因此,即使多个线程试图锁定互斥锁,也只有一个线程会成功。在拥有线程解锁该互斥锁之前,没有其他线程可以拥有该互斥锁。线程必须“轮流”访问受保护的数据。
这个也是实现线程同步的一种方法。
相关函数
- pthread_mutex_init(mutex,attr)
动态初始化初始化互斥变量.还可以静态pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER
;初始化互斥变量
pthread_mutex_lock (mutex)
指定锁定互斥变量。如果互斥锁已被其他线程锁定,则此调用将阻止调用线程,直到互斥锁被解锁。pthread_mutex_trylock (mutex)
尝试锁定互斥锁。但是,如果互斥锁已被锁定,则返回对应错误代码。可用于防止死锁条件。pthread_mutex_unlock (mutex)
解锁互斥锁。如果其他线程要获取用于处理受保护数据的互斥锁,则在线程完成对受保护数据的使用后。如果互斥锁已经解锁或者被其他线程拥有,解锁则会返回错误。
使用实例
//互斥锁的使用
- (IBAction)lockPthread:(id)sender {
pthread_attr_t attr;
pthread_t thread[5];
void *status;
sum = 0;
//初始化互斥锁
pthread_mutex_init(&mutexSum, NULL);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
for (NSInteger i =0 ; i<5; i++) {
pthread_create(&thread[i], &attr, testPthreadB, (void *)i);
}
pthread_attr_destroy(&attr);
for (NSInteger i =0 ;i<5;i++) {
pthread_join(thread[i],&status);
}
NSLog(@"sum = %lf",sum);
//销毁互斥锁
pthread_mutex_destroy(&mutexSum);
}
void *testPthreadB(void *t) {
int start,end,offset;
offset = (int)t;
start = offset *100;
end = start +100;
double mysum = 0;
for (NSInteger i = start; i
pthread 条件变量
条件变量为线程提供了另外一种同步方式。允许线程根据数据的实际值进行同步。条件变量需与互斥锁一起结合使用。
相关函数
- pthread_cond_init (condition,attr)
动态创建条件变量。同样也可以通过pthread_cond_t mycondT = PTHREAD_COND_INITIALIZER
静态创建。
attr
对象用于设置条件变量属性。只为条件变量定义了一个属性:process-shared,它允许条件变量被其他进程中的线程看到
-
pthread_cond_destroy (condition)
销毁条件变量
-
pthread_condattr_init (attr)
创建属性对象
-
pthread_condattr_destroy (attr)
销毁属性对象
-
pthread_cond_wait (condition,mutex)
阻塞调用线程,直到发出指定的条件。在锁定互斥锁时调用此方法,并在等待时自动释放互斥锁。收到信号并唤醒线程后,互斥锁将自动锁定以供线程使用。然后,我们需要在线程完成时解锁互斥锁。
-
pthread_cond_signal (condition)
用于向一个另外一个线程发送信号唤醒线程。应该在锁定互斥锁后调用它,并且必须解锁互斥锁才能完成
pthread_cond_wait
pthread_cond_broadcast (condition)
当有多个线程处于阻塞状态,用来取代pthread_cond_signal
使用实例
//线程阻塞和唤醒
- (IBAction)waitPthread:(id)sender {
count = 0;
pthread_t thread[3];
pthread_attr_t attr;
pthread_mutex_init(&myMutex, NULL);
pthread_attr_init(&attr);
pthread_cond_init(&myCond, NULL);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&thread[0], &attr, lookCount, (void *)1);
pthread_create(&thread[1], &attr, addCount, (void *)2);
pthread_create(&thread[2], &attr, addCount, (void *)3);
for (NSInteger i =0; i<3; i++) {
pthread_join(thread[i], NULL);
}
NSLog(@"线程执行完毕");
pthread_attr_destroy(&attr);
pthread_mutex_destroy(&myMutex);
pthread_cond_destroy(&myCond);
}
void *addCount(void *t) {
long threadID = (long)t;
for (NSInteger i =0; i
参考:
POSIX Threads Programming
下一篇:
iOS多线程学习二NSTread