多线程具体实现(下)

简介: 多线程具体实现

多线程全局变量共享

注意:如果共享局部变量使用下列方法失败

#include <pthread.h>
#include <semaphore.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void *thread1_func(void *arg)
{
    int    n;    
    int lfp = *(int *)arg;
    for (n = 0; n < 30; n++) {
        sleep(1);
        printf("AAAAAAAAAA\n");
        printf("A lfp = %d\n",lfp);
    }
    pthread_exit(NULL);
    //return NULL;
}
void *thread2_func(void *arg)
{
    int n;
    int lfp = *(int *)arg;
    for (n = 0; n < 30; n++) {
        sleep(1);
        printf("BBBBBBBBBB\n");
        printf("A lfp = %d\n",lfp);
    }
    return NULL;
}
int main(int argc, char *argv[])
{
    pthread_t tid1, tid2;
    int lfp = 10;
    if (pthread_create(&tid1, NULL, thread1_func, &lfp) != 0) {
        perror("main: pthread_create thread_1 failed");
        return 1;
    } else {
        printf("main: pthread_create thread_1 succeed!\n");
    }
    lfp = 15;
    if (pthread_create(&tid2, NULL, thread2_func, &lfp) != 0) {
        perror("main: pthread_create thread_2 failed");
        return 1;
    } else {
        printf("main: pthread_create thread_2 succeed!\n");
    }
    if (pthread_join(tid1, NULL) != 0) {
        perror("main: pthread_join thread_1 failed");
    }
    if (pthread_join(tid2, NULL) != 0) {
        perror("main: pthread_join thread_2 failed");
    }
    printf("main is exiting.\n");
    return 0;
}

如果运行结果

在线程A中局部变量理想值应该为10,线程B中局部变量理想值才应该为15,实际中两个都为15

解决方法

专门为局部变量申请内存,或尽量不用局部变量,不要将局部变量地址传入线程

#include <pthread.h>
#include <semaphore.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void *thread1_func(void *arg)
{
    int    n;    
    int lfp = *(int *)arg;
    for (n = 0; n < 30; n++) {
        sleep(1);
        printf("AAAAAAAAAA\n");
        printf("A lfp = %d\n",lfp);
    }
    free(arg);
    pthread_exit(NULL);
    //return NULL;
}
void *thread2_func(void *arg)
{
    int n;
    int lfp = *(int *)arg;
    for (n = 0; n < 30; n++) {
        sleep(1);
        printf("BBBBBBBBBB\n");
        printf("B lfp = %d\n",lfp);
    }
    free(arg);
    return NULL;
}
int main(int argc, char *argv[])
{
    pthread_t tid1, tid2;
    int lfp = 10;
    int *p = malloc(sizeof(int));
    *p = 10;
    if (pthread_create(&tid1, NULL, thread1_func, p) != 0) {
        perror("main: pthread_create thread_1 failed");
        return 1;
    } else {
        printf("main: pthread_create thread_1 succeed!\n");
    }
    lfp = 15;
    if (pthread_create(&tid2, NULL, thread2_func, &lfp) != 0) {
        perror("main: pthread_create thread_2 failed");
        return 1;
    } else {
        printf("main: pthread_create thread_2 succeed!\n");
    }
    if (pthread_join(tid1, NULL) != 0) {
        perror("main: pthread_join thread_1 failed");
    }
    if (pthread_join(tid2, NULL) != 0) {
        perror("main: pthread_join thread_2 failed");
    }
    printf("main is exiting.\n");
    return 0;
}

多线程打开文件共享

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int fd = -1;
void *thread1_func(void *arg)
{
    char buf[128] = {0};
    read(fd,buf,5);
    printf("thread1: buf = %s\n",buf);
    pthread_exit(NULL);
    //return NULL;
}
void *thread2_func(void *arg)
{
    char buf[128] = {0};
    read(fd,buf,5);
    printf("thread2: buf = %s\n",buf);
    return NULL;
}
int main(int argc, char *argv[])
{
    pthread_t tid1, tid2;
    fd = open("./lfp",O_RDWR);
    if(fd < 0){
        perror("open fail\n");
    }
    if (pthread_create(&tid1, NULL, thread1_func, NULL) != 0) {
        perror("main: pthread_create thread_1 failed");
        return 1;
    } else {
        printf("main: pthread_create thread_1 succeed!\n");
    }
    lfp = 15;
    if (pthread_create(&tid2, NULL, thread2_func, NULL) != 0) {
        perror("main: pthread_create thread_2 failed");
        return 1;
    } else {
        printf("main: pthread_create thread_2 succeed!\n");
    }
    if (pthread_join(tid1, NULL) != 0) {
        perror("main: pthread_join thread_1 failed");
    }
    if (pthread_join(tid2, NULL) != 0) {
        perror("main: pthread_join thread_2 failed");
    }
    printf("main is exiting.\n");
    return 0;
}

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int fd = -1;
void *thread1_func(void *arg)
{
    char buf[128] = {0};
    read(fd,buf,5);
    printf("thread1: buf = %s\n",buf);
    pthread_exit(NULL);
    //return NULL;
}
void *thread2_func(void *arg)
{
    fd = open("./lfp",O_RDWR);
    if(fd < 0){
        perror("open fail\n");
    }
    char buf[128] = {0};
    read(fd,buf,5);
    printf("thread2: buf = %s\n",buf);
    return NULL;
}
int main(int argc, char *argv[])
{
    pthread_t tid1, tid2;
    if (pthread_create(&tid1, NULL, thread1_func, NULL) != 0) {
        perror("main: pthread_create thread_1 failed");
        return 1;
    } else {
        printf("main: pthread_create thread_1 succeed!\n");
    }
    if (pthread_create(&tid2, NULL, thread2_func, NULL) != 0) {
        perror("main: pthread_create thread_2 failed");
        return 1;
    } else {
        printf("main: pthread_create thread_2 succeed!\n");
    }
    if (pthread_join(tid1, NULL) != 0) {
        perror("main: pthread_join thread_1 failed");
    }
    if (pthread_join(tid2, NULL) != 0) {
        perror("main: pthread_join thread_2 failed");
    }
    printf("main is exiting.\n");
    return 0;
}

多线程互斥锁

线程与进程的同步互斥比较

• 多线程共享同一个进程的地址空间

• 优点:

线程间很容易进行通信

通过全局变量实现数据共享和交换

• 缺点:

多个线程同时访问共享对象时需要引入同步和互斥机制

互斥锁

互斥锁主要用来保护临界资源

• 每个临界资源都由一个互斥锁来保护,任何时刻最多只能有一个线程能访问

该资源

• 使用规则:

线程必须先获得互斥锁才能访问临界资源,访问完资源后释放该锁。

如果无法获得锁,线程会阻塞直到获得锁为止

mutex函数

pthread_mutex_init
#include <pthread.h>
 int  pthread_mutex_init(pthread_mutex_t  *mutex,pthread_mutexattr_t *attr)

// 初始化互斥锁

函数参数

mutex:互斥锁

attr: 互斥锁属性 // NULL表示缺省属性

函数返回值

成功:0

出错:-1

Posix Mutex API

PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略

保证了资源分配的公平性。

PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞

争。

PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样保

证当不允许多次加锁时不出现最简单情况下的死锁。PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。

pthread_mutex_unlockpthread_mutex_lock

#include <pthread.h>
 int  pthread_mutex_unlock(pthread_mutex_t *mutex)// 释放互斥锁

函数参数

mutex:互斥锁

函数返回值

成功:0

出错:-1

#include <pthread.h>
 int  pthread_mutex_lock(pthread_mutex_t *mutex)// 申请互斥锁

函数参数

mutex:互斥锁

函数返回值

成功:0

出错:-1

举例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
//#define _LOCK_
unsigned int value1,value2, count=0;
pthread_mutex_t  mutex;
void *function(void *arg);
int main(int argc,  char *argv[])
{
    pthread_t  a_thread;
    if (pthread_mutex_init(&mutex, NULL) < 0)                                                                                                                                                          
    {
        perror("fail to mutex_init");
        exit(-1);
    }
    if (pthread_create(&a_thread, NULL, function, NULL) < 0)
    {
        perror("fail to pthread_create");
        exit(-1);
    }
    while ( 1 )
    {
        count++;
//#ifdef  _LOCK_
 //       pthread_mutex_lock(&mutex);
//#endif
        value1 = count;
        value2 = count;
//#ifdef  _LOCK_
//       pthread_mutex_unlock(&mutex);
//#endif
    }
    return 0;
 }
void  *function(void *arg)
{
     while ( 1 )
     {
#ifdef _LOCK_
        pthread_mutex_lock(&mutex);
#endif           
        if (value1 != value2)  
        {
            printf("count=%d , value1=%d, value2=%d\n",  count, value1, value2);
            usleep(100000);
        }     
#ifdef _LOCK_
        pthread_mutex_unlock(&mutex);
#endif
     }
     return  NULL;
 }

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
//#define _LOCK_
unsigned int value1,value2, count=0;
pthread_mutex_t  mutex;
void *function(void *arg);
int main(int argc,  char *argv[])
{
    pthread_t  a_thread;
    if (pthread_mutex_init(&mutex, NULL) < 0)                                                                                                                                                          
    {
        perror("fail to mutex_init");
        exit(-1);
    }
    if (pthread_create(&a_thread, NULL, function, NULL) < 0)
    {
        perror("fail to pthread_create");
        exit(-1);
    }
    while ( 1 )
    {
        count++;
#ifdef  _LOCK_
        pthread_mutex_lock(&mutex);
#endif
        value1 = count;
        value2 = count;
#ifdef  _LOCK_
        pthread_mutex_unlock(&mutex);
#endif
    }
    return 0;
 }
void  *function(void *arg)
{
     while ( 1 )
     {
#ifdef _LOCK_
        pthread_mutex_lock(&mutex);
#endif           
        if (value1 != value2)  
        {
            printf("count=%d , value1=%d, value2=%d\n",  count, value1, value2);
            usleep(100000);
        }     
#ifdef _LOCK_
        pthread_mutex_unlock(&mutex);
#endif
     }
     return  NULL;
 }

条件变量

• 条件变量是利用线程间共享的全局变量进行同步的一种机制。

• 主要包括两个动作:

一个线程等待“条件变量的条件成立”而挂起;

另一个线程使“条件成立”(给出条件成立信号)并唤醒挂起线程。

• 为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。对条件的测试是在互斥锁(互斥)的保护下进行的。

条件变量创建和注销

#include <pthread.h>
 int  pthread_cond_destroy(pthread_cond_t *cond)

函数参数

cond:条件变量

函数返回值

成功:0

出错:返回错误码

#include <pthread.h>
 int  pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t   *cond_attr)

函数参数

cond:条件变量

attr :通常为NULL。默认值是 PTHREAD_ PROCESS_PRIVATE,即此条件变量被同一进程内的各个线程使用。

函数返回值

成功:0

出错:返回错误码

条件变量等待

#include <pthread.h>
int  pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t   *mutex)

函数参数

cond:条件变量

mutex :互斥锁

函数返回值

成功:0

出错:返回错误码

条件变量唤醒

#include <pthread.h>
 int  pthread_cond_signal(pthread_cond_t *cptr)
//按入队顺序唤醒其中一个
int  pthread_cond_broadcast(pthread_cond_t *cptr)
唤醒所有等待线程

函数参数

cond:条件变量

函数返回值

成功:0

出错:返回错误码

实例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>   
#include <semaphore.h>
pthread_mutex_t mutex;//锁定标志 
pthread_cond_t cond;//唤醒条件变量
void *thread1_func(void *arg)
{
    int    n;    
    printf("enter t1\n");
    pthread_mutex_lock(&mutex);//锁定    
    printf("t1 lock mutex\n");
    for (n = 0; n < 3; n++) {
        sleep(1);
        printf("AAAAAAAAAA\n");
    }
    pthread_cond_signal(&cond);//唤醒单个线程
    printf("t1 signal cond to t2\n");    
    pthread_mutex_unlock(&mutex);//解锁
    printf("t1 unlock mutex\n");    
    pthread_exit(NULL);
    //return NULL;
}
void *thread2_func(void *arg)
{
    int n;
    printf("\t\tenter t2\n");
    pthread_mutex_lock(&mutex);//锁定, 阻塞前被锁上
    printf("\t\tt2 lock mutex and wait\n");    
    pthread_cond_wait(&cond,&mutex);
    printf("\t\tt2 wakeup\n");
    for (n = 0; n < 3; n++) {
        sleep(1);
        printf("\t\tBBBBBBBBBB\n");
    }
    pthread_mutex_unlock(&mutex);//解锁
    printf("\t\tt2 unlock mutex\n");    
    return NULL;
}
int main(int argc, char *argv[])
{
    pthread_t tid1, tid2;
    //生成互斥锁mutex,默认属性初始化
    pthread_mutex_init(&mutex,NULL);
    //生成一个唤醒变量,默认属性=?同一进程内的所有线程使用
    pthread_cond_init(&cond,NULL);
    if (pthread_create(&tid1, NULL, thread1_func, NULL) != 0) {
        perror("main: pthread_create thread_1 failed");
        return 1;
    } else {
        printf("main: pthread_create thread_1 succeed!\n");
    }
    if (pthread_create(&tid2, NULL, thread2_func, NULL) != 0) {
        perror("main: pthread_create thread_2 failed");
        return 1;
    } else {
        printf("main: pthread_create thread_2 succeed!\n");
    }
    if (pthread_join(tid1, NULL) != 0) {
        perror("main: pthread_join thread_1 failed");
    }
    if (pthread_join(tid2, NULL) != 0) {
        perror("main: pthread_join thread_2 failed");
    }
    pthread_cond_destroy(&cond);//释放阻塞唤醒变量
    pthread_mutex_destroy(&mutex);//释放互斥锁mutex资源
    printf("main is exiting.\n");
    return 0;
}


目录
相关文章
|
Ubuntu Windows
Ubuntu 20.04.2 LTS安装 最新版 微信(wine)
Ubuntu 20.04.2 LTS安装 最新版 微信(wine)
3552 0
Ubuntu 20.04.2 LTS安装 最新版 微信(wine)
|
程序员 C语言
C语言什么是库函数 库函数怎么使用 为什么发明库函数
C语言什么是库函数 库函数怎么使用 为什么发明库函数
110 0
|
7月前
|
图形学
Unity Text修改字间距
本文介绍了两种实现字间距调整的方法。第一种方法直接通过修改顶点位置实现字间距调整,代码简洁但换行时效果不佳。第二种方法引入了`Line`结构和对齐方式(左、中、右),能够处理多行文本并支持不同对齐方式,更加灵活和通用。两种方法均基于Unity的`BaseMeshEffect`类,通过重写`ModifyMesh`方法来调整UI文本的字间距。最终运行测试可验证效果。
|
10月前
|
人工智能 JSON 算法
Qwen2.5-Coder 系列模型在 PAI-QuickStart 的训练、评测、压缩及部署实践
阿里云的人工智能平台 PAI,作为一站式、 AI Native 的大模型与 AIGC 工程平台,为开发者和企业客户提供了 Qwen2.5-Coder 系列模型的全链路最佳实践。本文以Qwen2.5-Coder-32B为例,详细介绍在 PAI-QuickStart 完成 Qwen2.5-Coder 的训练、评测和快速部署。
Qwen2.5-Coder 系列模型在 PAI-QuickStart 的训练、评测、压缩及部署实践
|
编解码 测试技术 数据库
图书馆管理系统系统分析与设计(上)
图书馆管理系统系统分析与设计(上)
587 0
|
Java Linux Maven
Maven 仓库
Maven仓库管理Java构件,包括依赖与插件。仓库分本地、中央和远程。本地仓库在首次运行时创建,默认位于用户目录的`.m2/repository`,可自定义。Maven优先从本地仓库获取构件,缺失则从远程仓库下载,中央仓库是默认远程仓库,包含大量开源Java构件,由社区维护,可通过http://search.maven.org/搜索。
|
JavaScript Java 测试技术
基于SpringBoot+Vue的新闻推荐系统附带文章和源代码
基于SpringBoot+Vue的新闻推荐系统附带文章和源代码
343 3
|
自然语言处理 数据格式
【ChatIE】论文解读:Zero-Shot Information Extraction via Chatting with ChatGPT
【ChatIE】论文解读:Zero-Shot Information Extraction via Chatting with ChatGPT
304 1
|
NoSQL 关系型数据库 Linux
阿里云RDS购买Linux——安装redis服务
阿里云RDS购买Linux——安装redis服务
303 0
|
存储 设计模式 算法
队列同步器AQS-AbstractQueuedSynchronizer 原理分析
队列同步器AQS-AbstractQueuedSynchronizer 原理分析
232 0