ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

线程基础

2021-06-03 13:04:44  阅读:153  来源: 互联网

标签:线程 基础 cond pthread mutex sem NULL


个人学习随笔,仅做学习之用

【1】线程的概念

线程:是一个程序并发执行多种任务的机制。

并发:多个任务同时运行。(cpu以ns级别的速度进行进程调度,切换进程、线程)

进程上下文切换:

​ 上下文:运行一个程序所需要的所有资源;

​ 上下文切换:替换原有内容,是一个耗时操作。

为了提高系统的性能,引入了一个轻量级的进程概念,称之为线程。

线程:属于进程,每一个进程至少需要一个线程作为指令执行体,线程运行在进程空间内。

多线程:一个进程,可以运行多个线程。

线程是程序运行的最小单位

同一个进程下的线程,共享该进程的内存地址(每个线程共享其附属进程的所有资源)

  • 资源分配

    线程与线程之间共享进程的:

    ​ 1)数据段(全局变量,静态变量,堆)

    ​ 2)正文段

    ​ 3)文件描述符

    不共享:

    ​ 1)栈区:每个线程都有自己的展区,存放各自的局部变量

进程与线程的区别

  1. 进程之间,都有独立的虚拟空间,是独立的个体

    因此,进程与进程之间要实现数据传输,需要引入进程通信机制

  2. 属于同一进程下的线程,共享进程的虚拟地址空间,不需要通信机制。

  3. 进程是资源分配的最小单位,线程是程序执行的最小单位

  4. 创建子进程需要克隆父进程的所有资源,但是创建线程不需要,因为本身就共享进程资源。

    所以,创建多线程,比创建子进程效率高。

【2】线程常用的函数

man pthread_create

1)安装man手册

sudo apt-get install manpages-de manpages-de-dev manpages-dev glibc-doc manpages-posix-dev manpages-posix

Compile and link with -pthread

2)pthread_create

功能:创建线程;
头文件:
       #include <pthread.h>
原型:
       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);
参数:
    pthread_t *thread:存储创建后的线程;
	pthread_attr_t *attr:线程属性,填NULL,代表默认属性;
	void *(*start_routine) (void *):是线程的执行体,函数指针。回调函数。
        需要传入一个函数的地址,该指针能指向 返回值是void*类型,且参数列表是void*类型的函数;
    void *arg:传入回调函数的参数;
返回值:
    成功,返回0;
	失败,返回错误码.非0;

注意:

  1. 线程是依附于进程的,如果进程退出(主线程退出),则同一进程下的所有线程都会强制退出。
  2. 分支线程退出,不会影响其他线程运行;
  3. 主线程和分支线程是并行的,谁先运行不确定,一般来说,主线程会先运行。

3)pthread_exit

功能:退出当前线程;
头文件:
       #include <pthread.h>
原型:
       void pthread_exit(void *retval);
参数:
    void *retval:线程退出的状态值,可以是任意类型的数据地址,也可以填NULL;
				可以被pthread_join函数接收。

没有pthread_join,线程的资源没有被回收,类似进程的僵尸进程。

4)pthread_join

功能:阻塞等待子线程退出,并回收线程资源(相当于进程中的wait函数);
头文件:
       #include <pthread.h>
原型:
       int pthread_join(pthread_t thread, void **retval);
参数:
    pthread_t thread:指定要等待的线程;
	void **retval:存储的是 pthread_exit(void *retval)的参数的地址,如果不想接收,填NULL;
返回值:
    成功,返回0;
    失败,返回errno;
#include <stdio.h>
#include <pthread.h>
#include <string.h>

//方法2
int status = 2;


//线程执行体
void* handler(void*arg)
{
    printf("******线程******\n");

    //方法1
    //static int status = 2;
//  pthread_exit(&status);

    //方法3:
    pthread_exit((void*)2);
}

void* handler1(void*arg)
{
    sleep(1);
    printf("******线程1******\n");
    return NULL;
}

int main(int argc, const char *argv[])
{
    pthread_t tid1, tid2;
    if(pthread_create(&tid1, NULL, handler, NULL) != 0)
    {
        perror("pthread_create");
        return -1;
    }

    if(pthread_create(&tid2, NULL, handler1, NULL) != 0)
    {
        perror("pthread_create");
        return -1;
    }


    printf("主函数\n");
/*  
    //方法1,2                                                                                                                      
    int *status;
    pthread_join(tid1, (void**)&status);
    printf("%d\n", *status);
*/
    //方法3
    int status;
    pthread_join(tid1, (void**)&status);
    printf("%d\n", status);
    return 0;
}

5)pthread_cancel

功能:请求指定线程退出;
头文件:
       #include <pthread.h>
原型:
       int pthread_cancel(pthread_t thread);
参数:
    pthread_t thread:指定要退出的线程;发送成功,并不意味着线程退出;
返回值:
    成功,返回0;
	失败,返回error;

6)pthread_detach

功能:分离线程,线程退出后,自动回收线程资源;
头文件:
       #include <pthread.h>
原型:
       int pthread_detach(pthread_t thread);
参数:
    pthread_t thread:指定要分离的线程id;
返回值:
    成功,返回0;
	失败,返回错误码;

获取当前线程的tid号:
    pthread_self();

pthread_detach(pthread_self());

【3】线程的同步互斥机制

临界资源(共享资源):多个任务并发执行的时候,访问同一个资源,我们将这个资源称之为临界资源。

临界区:访问临界资源的代码,称之为临界区;

线程之间,如果要进行通信,需要引入同步互斥机制,避免产生竞态。保证任何一个时刻,只有一个线程处理临界资源。

同步互斥机制

  1. 互斥锁(pthread_mutex_t)
  2. 条件变量(pthread_cond_t)
  3. 信号量(sem_t)

1. 互斥锁

1)工作原理

  1. 对于要访问临界资源的线程,在访问之前,先申请互斥锁。

    如果申请上锁成功,则执行临界区代码,直到退出临界区,解开互斥锁。

    如果申请上锁失败,则说明互斥锁被别的线程占用,则线程进入休眠,等待互斥锁打开。

  2. 互斥锁会将临界区锁住,保证了临界区代码的完整性。

  3. 互斥锁又称之为二值信号量

2)pthread_mutex_init

功能:创建并初始化互斥锁;
头文件:
       #include <pthread.h>
原型:
       int pthread_mutex_init(pthread_mutex_t *mutex,  const pthread_mutexattr_t *mutexattr);
		pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
参数:
    pthread_mutex_t *mutex:存储申请及初始化后的互斥锁;
	pthread_mutexattr_t *mutexattr:互斥锁的属性,填NULL;
返回值:
    成功,返回0;
	失败,返回errno;

用宏的方式初始化
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

3)pthread_mutex_lock

功能:上锁;
头文件:
       #include <pthread.h>
原型:
       int pthread_mutex_lock(pthread_mutex_t *mutex);
参数:
    pthread_mutex_t *mutex:需要上锁的互斥锁的地址;
返回值:
    成功,返回0;
	失败,返回errno;

4)pthread_mutex_unlock

功能:解锁;
头文件:
       #include <pthread.h>
原型:
       int pthread_mutex_unlock(pthread_mutex_t *mutex);
参数:
    pthread_mutex_t *mutex:需要解开的互斥锁的地址;
返回值:
    成功,返回0;
	失败,返回errno;

5)pthread_mutex_destroy

功能:销毁初始化;
头文件:
       #include <pthread.h>
原型:      
       int pthread_mutex_destroy(pthread_mutex_t *mutex);
返回值:
    pthread_mutex_t *mutex:要销毁的互斥锁的地址;
返回值:
    成功,返回0;
	失败,返回errno;
#include <stdio.h>
#include <string.h>
#include <pthread.h>

//临界资源(共享资源)
char str[30] = "AAAAAAAAAAA|BBBBBBBBBB";

//互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;


void* handler1(void* arg)
{
    while(1)
    {   
        /*******临界区******/
        pthread_mutex_lock(&mutex);
        printf("%s\n", str);
        pthread_mutex_unlock(&mutex);
        /*******临界区******/
    }   
    pthread_exit(NULL);
}

//倒置
void* handler2(void* arg)
{
    char* start = str;
    char* end = str+strlen(str)-1;

    char temp = 0;
    while(1)
    {   
        start = str;
        end = str+strlen(str)-1;

        /*******临界区******/
        pthread_mutex_lock(&mutex);
        while(start < end)
        {
            temp = *start;
            *start = *end;
            *end = temp;
            start++;
            end--;
        }
        pthread_mutex_unlock(&mutex);
        /*******临界区******/
    }   
    pthread_exit(NULL);
}


int main(int argc, const char *argv[])
{
    /*  
    //创建并初始化互斥所
    if(pthread_mutex_init(&mutex, NULL)!=0)                                                                                                                                                                                            
    {
        perror("pthread_mutex_init");
        return -1;
    }
    */

    pthread_t tid1, tid2;
    if(pthread_create(&tid1, NULL, handler1, NULL) != 0)
    {   
        perror("pthread_create");
        return -1; 
    }   


    if(pthread_create(&tid2, NULL, handler2, NULL) != 0)
    {   
        perror("pthread_create");
        return -1; 
    }   

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    //销毁互斥所
    pthread_mutex_destroy(&mutex);

    return 0;
}

6)举例:

用两个线程拷贝一张图片,A线程拷贝前半部分,B线程拷贝后半部分

不能使用sleep函数

int size = lseek(fd_r, 0, SEEK_END);

#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>

typedef struct
{
    int fd_r;
    int fd_w;
    int size;
}__msg;

//互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

//拷贝前半部分
void* handler1(void* arg)
{
    __msg msg = *(__msg*)arg;

    /********临界区********/
    pthread_mutex_lock(&mutex);
    lseek(msg.fd_r, 0, SEEK_SET);
    lseek(msg.fd_w, 0, SEEK_SET);

    int i = 0;
    char c = 0;
    int res = 0;
    for(i=0; i<msg.size/2; i++)
    {
        res = read(msg.fd_r, &c, 1);
        if(res < 0)
        {
            perror("read");
            pthread_mutex_unlock(&mutex);
            pthread_exit(NULL);
        }

        if(write(msg.fd_w, &c, 1) < 0)
        {
            perror("write");
            pthread_mutex_unlock(&mutex);
            pthread_exit(NULL);
        }
    }

    printf("前半部分拷贝完毕\n");
    pthread_mutex_unlock(&mutex);
    /********临界区********/

    pthread_exit(NULL);
}

//拷贝后半部分
void* handler2(void* arg)
{                                                                                                       
    __msg msg = *(__msg*)arg;

    /********临界区********/
    pthread_mutex_lock(&mutex);
    lseek(msg.fd_r, msg.size/2, SEEK_SET);
    lseek(msg.fd_w, msg.size/2, SEEK_SET);

    int i = 0;
    char c = 0;
    int res = 0;
    while(1)
    {
        res = read(msg.fd_r, &c, 1);
        if(res < 0)
        {
            perror("read");
            break;
        }
        else if(0 == res)
        {
            break;
        }

        if(write(msg.fd_w, &c, 1) < 0)
        {
            perror("write");
            pthread_mutex_unlock(&mutex);
            pthread_exit(NULL);
        }
    }
    printf("后半部分拷贝完毕\n");
    pthread_mutex_unlock(&mutex);
    /********临界区********/


    pthread_exit(NULL);
}


int main(int argc, const char *argv[])
{
    __msg msg;

    msg.fd_r = open("1.png", O_RDONLY);
    msg.fd_w = open("2.png", O_WRONLY|O_CREAT|O_TRUNC, 0664);
    if(msg.fd_r < 0 || msg.fd_w < 0)
    {
        perror("open");
        return -1;
    }

    //计算大小
    msg.size = lseek(msg.fd_r, 0, SEEK_END);
    lseek(msg.fd_r, 0, SEEK_SET);


    pthread_t tid1, tid2;
    if(pthread_create(&tid1, NULL, handler1, (void*)&msg) != 0)
    {
        perror("pthread_create");
        return -1;
    }


    if(pthread_create(&tid2, NULL, handler2, (void*)&msg) != 0)
    {
        perror("pthread_create");
        return -1;
    }


    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    //销毁互斥所
    pthread_mutex_destroy(&mutex);
    close(msg.fd_r);
    close(msg.fd_w);

    return 0;
}

7)死锁

拥有锁资源的任务,没有释放锁

  1. 持有互斥锁的任务,异常退出,没有释放锁资源。
  2. 同一互斥锁重复上锁。
  3. 互斥锁交叉嵌套

2. 条件变量

1)工作原理

  1. 将不访问共享资源的线程直接睡眠
  2. 如果线程需要访问,则通过其他线程唤醒。

2)pthread_cond_init

功能:创建并初始化条件变量;
头文件:
       #include <pthread.h>
原型:
       pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
       int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
参数:
    pthread_cond_t *cond:存储初始化后的条件变量;
	pthread_condattr_t *cond_attr:填NULL;
返回值:
    成功,返回0;
	失败,返回errno;

3)pthread_cond_wait

功能:让线程进入睡眠,等待被唤醒;
头文件:
       #include <pthread.h>
原型:  
       int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
参数:
    pthread_cond_t *cond:指定的条件变量;
	pthread_mutex_t *mutex:指定互斥锁;
返回值:
    成功,返回0;
	失败,返回errno;

函数的步骤:
1.解开互斥锁,同时阻塞当前线程;
2.等待被唤醒;
3.唤醒成功后,尝试上锁;
4.如果上锁成功,则从当前位置继续向后运行;
5.如果上锁失败,则从当前位置继续阻塞;

注意:
    唤醒,且成功上锁后,是从上一次睡觉的地方继续运行的。不会从线程头部开始运行。

4)pthread_cond_signal

功能:唤醒条件变量;
头文件:
       #include <pthread.h>
原型:
       int pthread_cond_signal(pthread_cond_t *cond);
参数:
    pthread_cond_t *cond:指定要唤醒的条件变量;
返回值:
    成功,返回0;
    失败,返回errno;

5)pthread_cond_destroy

功能:销毁条件变量;
头文件:
       #include <pthread.h>
原型:
       int pthread_cond_destroy(pthread_cond_t *cond);
参数:
    pthread_cond_t *cond:指定要销毁的互斥锁;
返回值:
    成功,返回0;
	失败,返回errno;
#include <stdio.h>
#include <string.h>
#include <pthread.h>

//互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//条件变量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int flag = 1;   //1.海绵宝宝,2.天线宝宝

//打印海绵宝宝
void* handler1(void* arg)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);

        //如果不是海绵宝宝,则进入if条件为真
        if(flag != 1)
        {
            //1.让当前线程休眠
            //2.打开互斥锁
            pthread_cond_wait(&cond, &mutex);
        }
        printf("*****海绵宝宝\n");
        flag = 2;
        pthread_mutex_unlock(&mutex);
        pthread_cond_signal(&cond);
    }

    pthread_exit(NULL);
}

//打印天线宝宝
void* handler2(void* arg)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);
        if(flag != 2)
        {
            //1.让当前线程休眠
            //2.打开互斥锁
            pthread_cond_wait(&cond, &mutex);
            //3.被唤醒后,尝试上锁
            //4.如果上锁失败,则继续休眠
            //5.如果上锁成功,则从当前位置继续向下执行.
        }
        printf("--天线宝宝\n");
        flag = 3;
        pthread_mutex_unlock(&mutex);
        pthread_cond_signal(&cond);
    }
    pthread_exit(NULL);
}

/*
//打印花园宝宝
void* handler3(void* arg)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);
        if(flag != 3)
        {
            //1.让当前线程休眠
            //2.打开互斥锁
            pthread_cond_wait(&cond, &mutex);
            //3.被唤醒后,尝试上锁
            //4.如果上锁失败,则继续休眠
            //5.如果上锁成功,则从当前位置继续向下执行.
        }
        printf("++++++++++++++花园宝宝\n");
        flag = 1;
        pthread_mutex_unlock(&mutex);
        pthread_cond_signal(&cond);
    }
    pthread_exit(NULL);
}
*/

int main(int argc, const char *argv[])
{
    /*
    //创建并初始化互斥所
    if(pthread_mutex_init(&mutex, NULL)!=0)
    {
        perror("pthread_mutex_init");
        return -1;
    }

    //创建并初始化条件变量
    if(pthread_cond_init(&cond, NULL) != 0)
    {
        perror("pthread_cond_init");
        return -1;
    }

    */

    pthread_t tid1, tid2, tid3;
    if(pthread_create(&tid1, NULL, handler1, NULL) != 0)
    {
        perror("pthread_create");
        return -1;
    }


    if(pthread_create(&tid2, NULL, handler2, NULL) != 0)
    {
        perror("pthread_create");
        return -1;
    }
/*
    if(pthread_create(&tid3, NULL, handler3, NULL) != 0)
    {
        perror("pthread_create");
        return -1;
    }
*/                                                                                                                                                           
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    pthread_join(tid3, NULL);

    //销毁互斥所
    pthread_mutex_destroy(&mutex);

    //销毁互斥所
    pthread_cond_destroy(&cond);

    return 0;
}

6)条件变量的基本格式

根据需求修改flag和todo something位置

#include <stdio.h>
#include <pthread.h>

//初始化条件变量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

int flag = 1;       

void* handler1(void* arg)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);
        if(flag != 1)
        {
            //1.让当前线程休眠
            //2.打开互斥锁
            pthread_cond_wait(&cond, &mutex);
            //3.被唤醒后,尝试上锁
            //4.如果上锁失败,继续休眠
            //5.如果上锁成功,则从当前位置继续向下运行
        }
        
        //todo something
        printf("111111\n");

        flag = 2;
        pthread_mutex_unlock(&mutex);
        pthread_cond_signal(&cond);
    }
    pthread_exit(NULL);
}

void* handler2(void* arg)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);
        if(flag != 2)
        {
            //1.让当前线程休眠
            //2.打开互斥锁,
            pthread_cond_wait(&cond, &mutex);
            //3.被唤醒后,立即上锁
            //4.如果上锁失败,继续休眠
            //5.如果上锁成功,则从当前位置继续向下运行

        }
        //todo something
        printf("2222222\n");
        
        
        flag = 1;
        pthread_mutex_unlock(&mutex);
        pthread_cond_signal(&cond);
    }

    pthread_exit(NULL);
}

int main(int argc, const char *argv[])
{

    pthread_t tid1, tid2;
    pthread_create(&tid1, NULL, handler1, NULL);                                                                                                                                                       
    pthread_create(&tid2, NULL, handler2, NULL);


    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);
    return 0;
}

3. 信号量

1)工作原理

  1. 对于访问共享资源的线程,都去执行申请信号量的操作。

    当信号量大于0,如果申请信号量成功,则信号量-1;

    当信号量为0,则申请信号量操作会阻塞,线程进入休眠等待阶段。

  2. 互斥锁又称之为二值信号量,只允许一个线程进入临界区

  3. 信号量允许多个线程同时进入临界区

  4. PV操作:实现线程、进程同步互斥的有效方式

    P:申请信号量,-1操作

    V:释放信号,+1操作

2)sem_init

功能:创建并初始化信号量;
头文件:
       #include <semaphore.h>
原型:
       int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
    sem_t *sem:存储创建并初始化后的信号量;
	int pshared:共享标识;
			0,用于线程;
            非0,用于进程;
	unsigned int value:信号量的初始值;
返回值:
    成功,返回0;
	失败,返回-1,更新errno;

3)sem_destroy

       #include <semaphore.h>

       int sem_destroy(sem_t *sem);

4)sem_wait(-1)

功能:申请信号量;P操作:-1;
	1.如果申请前,信号量为0,则该线程阻塞,进入休眠;
	2.如果申请前,信号量大于0,则申请成功,信号量-1,函数立即返回;
头文件:
       #include <semaphore.h>
原型:
       int sem_wait(sem_t *sem);
参数:
    sem_t *sem:指定需要申请的信号量;
返回值:
    成功,返回0;
	失败,返回-1;

5)sem_post(+1)

功能:释放信号量,V操作:+1;
头文件:
       #include <semaphore.h>
原型:
       int sem_post(sem_t *sem);
参数:
    sem_t *sem:指定信号量;
返回值:
    成功,返回0;
	失败,返回-1,更新errno;

6)sem_getvalue

功能:获取信号量的值;
头文件:
       #include <semaphore.h>
原型:
       int sem_getvalue(sem_t *sem, int *sval);
参数:
    sem_t *sem:指定信号量;
	int *sval:存储获取到的信号量的值;
返回值:
    成功,返回0;
	失败,返回-1,更新errno;

7)举例

1.用信号量的方式实现一个线程倒置,一个线程打印
2.用信号量的方式实现倒置一次打印一次。
例1:
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>

//临界资源(共享资源)
char str[30] = "AAAAAAAAAAA|BBBBBBBBBB";

//互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;


void* handler1(void* arg)
{
    while(1)
    {
        /*******临界区******/
    //  pthread_mutex_lock(&mutex);
        sem_wait((sem_t*)arg);
        printf("%s\n", str);
    //  pthread_mutex_unlock(&mutex);
        sem_post((sem_t*)arg);                                                                                                                                                                                                                   
        /*******临界区******/
    }
    pthread_exit(NULL);
}

//倒置
void* handler2(void* arg)
{
    char* start = str;
    char* end = str+strlen(str)-1;

    char temp = 0;
    while(1)
    {
        start = str;
        end = str+strlen(str)-1;

        /*******临界区******/
        //pthread_mutex_lock(&mutex);
        sem_wait((sem_t*)arg);
        while(start < end)
        {
            temp = *start;
            *start = *end;
            *end = temp;
            start++;
            end--;
        }
        //pthread_mutex_unlock(&mutex);
        sem_post((sem_t*)arg);
        /*******临界区******/
    }
    pthread_exit(NULL);
}


int main(int argc, const char *argv[])
{
    sem_t sem;
    if(sem_init(&sem, 0, 1) < 0)
    {
        perror("sem_init");
        return -1;
    }


    pthread_t tid1, tid2;
    if(pthread_create(&tid1, NULL, handler1, (void*)&sem) != 0)
    {
        perror("pthread_create");
        return -1;
    }


    if(pthread_create(&tid2, NULL, handler2, (void*)&sem) != 0)
    {
        perror("pthread_create");
        return -1;
    }

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    //销毁互斥所
    pthread_mutex_destroy(&mutex);

    return 0;
}
例2:
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>

//临界资源(共享资源)
char str[30] = "AAAAAAAAAAA|BBBBBBBBBB";

sem_t sem1;
sem_t sem2;

void* handler1(void* arg)
{
    while(1)
    {
        /*******临界区******/
        sem_wait(&sem1);
        printf("%s\n", str);
    //  pthread_mutex_unlock(&mutex);
        sem_post(&sem2);                                                                                                                                                                                                                                                                                     
        /*******临界区******/
    }
    pthread_exit(NULL);
}

//倒置
void* handler2(void* arg)
{
    char* start = str;
    char* end = str+strlen(str)-1;

    char temp = 0;
    while(1)
    {
        start = str;
        end = str+strlen(str)-1;

        /*******临界区******/
        sem_wait(&sem2);
        while(start < end)
        {
            temp = *start;
            *start = *end;
            *end = temp;
            start++;
            end--;
        }
        sem_post(&sem1);
        /*******临界区******/
    }
    pthread_exit(NULL);
}


int main(int argc, const char *argv[])
{
    //sem1控制打印
    if(sem_init(&sem1, 0, 1) < 0)
    {
        perror("sem_init");
        return -1;
    }
    //sem2控制倒置
    if(sem_init(&sem2, 0, 0) < 0)
    {
        perror("sem_init");
        return -1;
    }


    pthread_t tid1, tid2;
    if(pthread_create(&tid1, NULL, handler1, NULL) != 0)
    {
        perror("pthread_create");
        return -1;
    }


    if(pthread_create(&tid2, NULL, handler2, NULL) != 0)
    {
        perror("pthread_create");
        return -1;
    }

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    //销毁信号量
    sem_destroy(&sem1);
    sem_destroy(&sem2);

    return 0;
}

标签:线程,基础,cond,pthread,mutex,sem,NULL
来源: https://www.cnblogs.com/yang-tai/p/14844735.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有