提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、线程同步
互斥锁,线程信号量,条件变量
1.互斥锁
1、定义一个互斥锁(也是一个变量)
pthread_mutex_t mutex;
2、初始化锁:预设互斥锁的初始值
pthread_mutex_mutex = PTHREAD_MUTEX_(INITIALIZER)(不常用)
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr )
功能:
初始化定义的互斥锁(就是设置互斥锁所需要的值)
返回值:
总是返回0,所以这个函数不需要进行错误处理
参数:
mutex:互斥锁,需要我们自己定义
3、加锁解锁
pthread_mutex_lock(&mutex);(阻塞加锁)
pthread_mutex_trylock()(非阻塞加锁)当锁被占有时返回EBUSY而不是挂起等待
pthread_mutex_unlock(&mutex)访问
4、进程退出时销毁互斥锁
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define MAX_SIZE 1024
char buffer[MAX_SIZE];
struct message
{
int fd;
//pthread_mutex_t mutex;
};
pthread_mutex_t mutex;
//定义一个互斥锁
void *thread1(void *arg)
{
struct message msg = *((struct message *)arg);
int fd = msg.fd;
while(1)
{
pthread_mutex_lock(&mutex);
write(fd,"hello",5);
write(fd,"world\n",6);
//sleep(2);
pthread_mutex_unlock(&mutex);
}
}
void *thread2(void *arg)
{
struct message msg = *((struct message *)arg);
int fd = msg.fd;
while(1)
{
pthread_mutex_lock(&mutex);
write(fd, "hhhhh", 5);
write(fd, "wwwww\n", 6);
//sleep(2);
pthread_mutex_unlock(&mutex);
}
}
int main()
{
pthread_t id1;
struct message msg;
int fd = open("./text.txt",O_RDWR|O_CREAT|O_APPEND, 0644);
if(fd < 0)
{
perror("open file error!");
exit(1);
}
msg.fd = fd;
pthread_mutex_init(&mutex, NULL);
//预设互斥锁的初始值
if(pthread_create(&id1, NULL, thread1,(void *)(&msg) ) != 0)
{
perror("pthread_create error!\n");
exit(1);
}
pthread_t id2;
if(pthread_create(&id2, NULL, thread2, (void *)(&msg)) != 0)
{
perror("pthread_create error!\n");
exit(1);
}
sleep(2);
pthread_cancel(id2);
pause();
return 0;
}
二、线程信号量
1.线程信号量使用步骤
1、定义信号量集
sem_t sem [3]
线程信号量集合其实就是一个数组,数组中每一个元素就是一个信号量
(sem[0]:第一个信号量
sem[1]:第二个信号量
sem[2]:第三个信号量)
2、初始化集合中的每个信号量
man手册查看
头文件
#include<semaphore.h>
函数原型
int sem_init(sem_t *sem,int pthread,unsigned int value)
功能:
初始化线程信号量集合中的某个信号量,给它设定一个初值
返回值:
成功返回0,失败返回-1,errno被设置
信号量的错误号不是返回的,而是直接设置到errno
value:初始化值(对于二进制信号量来说,要么是1,要么是0)
pshared:0:给线程使用,!0可以给进程使用
3、p、v操作
P操作:
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
V操作:
int sem_post(sem_t *sem);
sem_wait value
假若你获得的时候被人已经获得了这个信号量(value值减一(在内核里加减)),你阻塞
4、进程结束时,删除信号量集合
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define MAX_SIZE 1024
char buffer[MAX_SIZE];
struct message
{
int fd;
//pthread_mutex_t mutex;
};
pthread_mutex_t mutex;
sem_t sem[1];
void *thread1(void *arg)
{
struct message msg = *((struct message *)arg);
int fd = msg.fd;
while(1)
{
//pthread_mutex_lock(&mutex);
sem_wait(&sem[0]);
write(fd,"hello",5);
write(fd,"world\n",6);
//sleep(2);
//pthread_mutex_unlock(&mutex);
sem_post(&sem[0]);
}
}
void *thread2(void *arg)
{
struct message msg = *((struct message *)arg);
int fd = msg.fd;
while(1)
{
sem_wait(&sem[0]);
//pthread_mutex_lock(&mutex);
write(fd, "hhhhh", 5);
write(fd, "wwwww\n", 6);
//sleep(2);
//pthread_mutex_unlock(&mutex);
sem_post(&sem[0]);
}
}
int main()
{
pthread_t id1;
struct message msg;
int fd = open("./text.txt",O_RDWR|O_CREAT|O_APPEND, 0644);
if(fd < 0)
{
perror("open file error!");
exit(1);
}
msg.fd = fd;
pthread_mutex_init(&mutex, NULL);
sem_init(&sem, 0, 1);
if(pthread_create(&id1, NULL, thread1,(void *)(&msg) ) != 0)
{
perror("pthread_create error!\n");
exit(1);
}
pthread_t id2;
if(pthread_create(&id2, NULL, thread2, (void *)(&msg)) != 0)
{
perror("pthread_create error!\n");
exit(1);
}
sleep(2);
pthread_cancel(id2);
pause();
return 0;
}
练习:
线程1输出11111
线程2输出22222
线程3输出33333
11111
22222
33333
11111
22222
33333
条件变量(和互斥锁配和使用)
一条线程做自加,一条线程输出(当自加变量到5输出之后自加变量清零)
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
int count = 0;
pthread_mutex_t mutex;
void *add_1(void *arg)
{
while(1)
{
pthread_mutex_lock(&mutex);
count++;
sleep(1);
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
void *print(void *arg)
{
while(1)
{
pthread_mutex_lock(&mutex);
if(count == 5)
{
printf("%d\n",count);
count = 0;
}
sleep(1);
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
int main()
{
pthread_t id1;
pthread_t id2;
int ret;
pthread_mutex_init(&mutex, NULL);
ret = pthread_create(&id1, NULL, add_1, NULL);
if(ret != 0)
{
perror("thread create error!");
exit(1);
}
ret = pthread_create(&id2, NULL, print, NULL);
if(ret != 0)
{
perror("thread create error!");
exit(1);
}
pthread_join(id1, NULL);
pthread_join(id2, NULL);
return 0;
}
三、条件变量(和互斥锁配和使用)
条件变量的主要作用(线程协同):主线程对count+1,次线程发现当count==5时输出count值并将count清零
多线程配合工作时,当线程检测到某条件不满足时就休眠,直到别的线程条件准备好,然后通过别的条件变量将其叫醒
使用步骤
1、定义一个条件变量
pthread_cond_t
2、初始化
pthread cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
功能:
初始化条件变量,与互斥锁类似
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
返回值:
成功返回0,不成功返回非零错误号
参数
cond:条件变量
attr:属性一般是NULL
3、使用条件变量
4、删除条件变量,也需要把互斥锁删除
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
int count = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;
void *add_1(void *arg)
{
while(1)
{
pthread_mutex_lock(&mutex);
count++;
if(count == 5)
{
pthread_cond_signal(&cont);
}
sleep(1);
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
void *print(void *arg)
{
while(1)
{
pthread_mutex_lock(&mutex);
if(count != 5)
{
pthread_cond_wait(&cond, &mutex);
count = 0;
}
printf("count = %d\n",count);
sleep(1);
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
int main()
{
pthread_t id1;
pthread_t id2;
int ret;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
ret = pthread_create(&id1, NULL, add_1, NULL);
if(ret != 0)
{
perror("thread create error!");
exit(1);
}
ret = pthread_create(&id2, NULL, print, NULL);
if(ret != 0)
{
perror("thread create error!");
exit(1);
}
pthread_join(id1, NULL);
pthread_join(id2, NULL);
return 0;
}