iOS多线程学习(一)pthread

POSIX线程

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

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

常用函数说明

关于完整相关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 = <NSThread: 0x600001e5edc0>{number = 3, name = (null)} threadID0
 currentThread = <NSThread: 0x600001e5ecc0>{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<end; i++) {
        mysum +=i;
    }
    //加锁
    pthread_mutex_lock(&mutexSum);
    sum +=mysum;
    NSLog(@"被访问thread %ld",offset);
    //解锁
    pthread_mutex_unlock(&mutexSum);
    pthread_exit((void *)t);
}
  

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<limit; i++) {
        pthread_mutex_lock(&myMutex);
        count ++;
        if (count == limit) {
            pthread_cond_signal(&myCond);
            NSLog(@"addcount():thread %ld count = %d 数量已经达到设定值\n",threadID,count);
        }
         NSLog(@"addcount():thread %ld count = %d 将要解锁\n",threadID,count);
        pthread_mutex_unlock(&myMutex);
        NSLog(@"addcount():thread %ld解锁完毕\n",threadID);
    }
    pthread_exit(NULL);
}

void *lookCount(void *t) {
     long threadID = (long)t;
    NSLog(@"lookCount():start thread %ld\n",threadID);
    pthread_mutex_lock(&myMutex);
    while (count<limit) {
        pthread_cond_wait(&myCond, &myMutex);
        NSLog(@"lookCount(): thread %ld 信号收到 count = %d \n",threadID,count);
    }
    count +=10;
    NSLog(@"lookCount():thread %ld count = %d 将要解锁\n",threadID,count);
    pthread_mutex_unlock(&myMutex);
    pthread_exit(NULL);
}
输出结果

参考:
POSIX Threads Programming

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容

  • 转自:Youtherhttps://www.cnblogs.com/youtherhome/archive/201...
    njukay阅读 1,610评论 0 52
  • 简介 线程创建 线程属性设置 线程参数传递 线程优先级 线程的数据处理 线程的分离状态 互斥锁 信号量 一 线程创...
    第八区阅读 8,554评论 1 6
  • linux编程-线程 MUTEX 一.概述 互斥量是线程同步的一...
    Aska偶阵雨阅读 477评论 0 0
  • Q:为什么出现多线程? A:为了实现同时干多件事的需求(并发),同时进行着下载和页面UI刷新。对于处理器,为每个线...
    幸福相依阅读 1,576评论 0 2
  • 今天熊鑫对聊天记录的剖析很受启发。 聊天节奏,气氛,提问不能太紧凑,要穿插。 维护的目的是吸引,产生链接。不管顾客...
    星星Fineyoga_7bf2阅读 147评论 0 1