一、创建线程
函数
- pthread_self()
- 获取线程ID。其作用对应进程中 getpid() 函数。
- 成功: 0 失败: 无
- pthread_create()
- 创建一个新线程。 对应进程中 fork() 函数。
- int pthread_create(phtread_t *thread, const pthread_attr, void *( *start_routine)(void *), void *arg);
- 返回值
- 成功:0
- 失败:错误号
- 参数:
- 参数一:传出参数,保存系统为我们分配好的线程ID
- 参数二:通常传NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。
- 参数三:函数指针,指向线程主函数,该函数运行结束,则线程结束。
- 参数四:线程主函数执行期间所使用的参数。
实现
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
void *tfn(void *arg){
//线程id 用来在进程当中标识线程身份。
printf("thread: pid = %d, tid = %lu\n", getpid(), pthread_self());
return NULL;
}
int main(int argc, char *argv[]){
pthread_t tid;
printf("main: pid = %d, tid = %lu\n", getpid(), pthread_self());
int ret = pthread_create(&tid, NULL, tfn, NULL);
if(ret != 0){
perror("pthread_create error");
}
//确保子线程创建完之前,主线程没有结束
sleep(1);
return 0;
}
现象
二、使用互斥锁使共享数据同步
同步即协同步调,按预定的先后次序运行。
在没有加锁之前
由于共享、竞争而没有加任何同步机制,导致产生于时间有关的错误,造成数据混乱。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include<unistd.h>
void *tfn(void *arg){
srand(time(NULL));
while(1) {
printf("hello---");
sleep(rand() % 3); //模拟长时间操作共享资源,导致cpu易主,产生与时间有关的错误
printf("---word\n");
sleep(rand() % 3);
}
return NULL;
}
int main(void){
pthread_t tid;
srand(time(NULL));
pthread_create(&tid, NULL, tfn, NULL);
while(1) {
printf("HELLO====");
sleep(rand() % 3);
printf("===WORLD\n");
sleep(rand() % 3);
}
pthread_join(tid, NULL);
return 0;
}
现象
加锁之后
使用mutex(互斥量、互斥锁)一般步骤:
- pthread_mutex lock; 创建锁
- pthread_mutex_init; 初始化
- pthread_mutex_lock; 加锁
- 访问共享数据(stdout)
- pthrad_mutex_unlock(); 解锁
- pthread_mutex_destroy(); 销毁锁
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include<unistd.h>
pthread_mutex_t mutex; //1、定义一把互斥锁
void *tfn(void *arg){
srand(time(NULL));
while(1) {
pthread_mutex_lock(&mutex); //加锁
printf("hello---");
sleep(rand() % 3); //模拟长时间操作共享资源,导致cpu易主,产生与时间有关的错误
printf("---word\n");
pthread_mutex_unlock(&mutex); //解锁
sleep(rand() % 3);
}
return NULL;
}
int main(void){
pthread_t tid;
srand(time(NULL));
int ret = pthread_mutex_init(&mutex, NULL); //2.初始化
if(ret != 0){
fprintf(stderr, "mutex init error:%s\n", strerror(ret));
exit(1);
}
pthread_create(&tid, NULL, tfn, NULL);
while(1) {
pthread_mutex_lock(&mutex); //加锁
printf("HELLO====");
sleep(rand() % 3);
printf("====WORLD\n");
pthread_mutex_unlock(&mutex); //解锁
sleep(rand() % 3);
}
pthread_join(tid, NULL);
phtread_mutex_destroy(&mutex); //6.销毁互斥锁
return 0;
}
现象
三、生产者消费者
生产者:
- 生产数据
- 加锁 pthread_mutex_lock(&mutex)
- 将数据放置到 公共区域
- 解锁 pthread_mutex_unlock(&mutex)
- 通知阻塞在条件变量上的线程
- pthread_cond_signal()
- pthread_cond_broadcast()
- 循环生产后续数据
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
void err_thread(int ret, char *str){
if(ret != 0){
fprintf(stderr, "%s:%s\n", str, strerror(ret));
pthread_exit(NULL);
}
}
struct msg{ //定义公共变量
int num;
struct msg *next;
};
struct msg *head; //头指针
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //互斥量
pthread_cond_t has_data = PTHREAD_COND_INITIALIZER; //条件变量
void *produser(void *arg){
while(1){
struct msg *mp = malloc(sizeof(struct msg));
mp->num = rand() % 1000;
printf("----produce %d\n", mp->num);
pthread_mutex_lock(&mutex); //加锁
mp->next = head; //写数据
head = mp;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&has_data); //唤醒阻塞在条件变量 has_data 上的线程
sleep(rand() % 3);
}
return NULL;
}
void *consumer(void *arg){
while(1){
struct msg *mp;
pthread_mutex_lock(&mutex); //加锁 互斥量
if(head == NULL){
pthread_cond_wait(&has_data, &mutex); //阻塞等待条件变量解锁后,pthread_cond_wait 返回时,重新加锁 mutex
}
mp = head;
head = mp->next;
pthread_mutex_unlock(&mutex); //解锁
printf("++++consumer: %d\n", mp->num);
free(mp);
sleep(rand() % 3);
}
return NULL;
}
int main(int argc, char *argv[]){
int ret;
pthread_t pid, cid;
srand(time(NULL));
ret = pthread_create(&pid, NULL, produser, NULL); //生产者
if(ret != 0){
err_thread(ret, "pthread_create produser error");
}
ret = pthread_create(&cid, NULL, consumer, NULL); //消费者
if(ret != 0){
err_thread(ret, "pthread_create consumer error");
}
pthread_join(pid, NULL);
pthread_join(cid, NULL);
return 0;
}
现象