iOS多线程学习(一)pthread

POSIX线程

(POSIX threads),简称Pthreads,是线程的POSIX标准。该标准定义了创建和操纵线程的一整套API。在类Unix操作系统(Unix、Linux、Mac OS X等)中,都使用Pthreads作为操作系统的线程.(来源百度百科)
POSIX线程提供了一个用于创建线程的基于C的接口。

使用pthread之前,我们需要引用其对应的库头文件#import

常用函数说明

关于完整相关pthreadAPI,可参考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
iOS多线程学习(一)pthread_第1张图片
输出结果

参考:
POSIX Threads Programming

下一篇:
iOS多线程学习二NSTread

你可能感兴趣的:(iOS多线程学习(一)pthread)