pthread不是linux下默认的库,有可能需要安装。
sudo apt-get install glibc-doc
sudo apt-get install manpages-posix-dev
通过man pthread_creat
查看man pages中关于pthread的手册。
#include
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
// Compile and link with -pthread.
这里讲下void *
是什么意思:无类型指针”,可以指向任何数据类型。
int *p1 = nullptr;
void *p2;
p2 = p1;
p1 = (int *)p2;
#include
#include
#include
void *print(void *argv) {
printf("I am a thread, pid = %d, tid = %lu\n", getpid(), pthread_self());
return argv;
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, print, NULL);
printf("I am a main thread, pid = %d, tid = %lu\n", getpid(), pthread_self());
sleep(1);
return 0;
}
每次写makefile很麻烦,推荐个方法。
# 如果是bash就是~/.bashrc, 我用的是zsh, ~/.zshrc
vim ~/.zshrc
# 在最后添加这一句话,前提是你在家目录下有bin文件,bin文件下有写好的makefile文件
alias echomake="cat ~/bin/makefile >> makefile"
# alias有起别名的作用,把"cat ~/bin/makefile >> makefile"这个命令起别名为echomake
source ~/.zshrc
# 注:要是使用的是bash, 就把zshrc换成bash
这样我们每次只需要在终端输入echomake
就会在当前目录生成一个编写好的模板makefile,编写makefile可以参考我的 makefile简单使用 ,希望对大家有帮助。
通过pthread_exit()
退出线程。不能用exit()
退出,这样会导致整个线程退出。
阻塞等待回收。
man pthread_join
#include
int pthread_join(pthread_t thread, void **retval);
Compile and link with -pthread.
#include
#include
#include
#include
#include
void *print(void *arg) {
printf("I am a thread, tid = %lu\n", pthread_self());
int *ret = new int(100);
return (void *)ret; // 这里返回的是100的地址,不是100!!!
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, print, NULL);
printf("I am main thread, tid = %lu\n", pthread_self());
void *ret = NULL;
pthread_join(tid, &ret); // 这里的&ret是地址的地址了。
// 这里&ret才是二级指针变量retval的地址
// std::cout << *(int *)ret << std::endl;
printf("ret = %d\n", *(int *)ret);
return 0;
}
我觉得代码应该是这样子写的,还有这种写法的。
#include
#include
#include
#include
void *print(void *arg) {
printf("I am a thread, tid = %lu\n", pthread_self());
return (void *)100;
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, print, NULL);
printf("I am main thread, tid = %lu\n", pthread_self());
void *ret;
pthread_join(tid, &ret);
printf("ret = %d\n", (int)ret);
return 0;
}
这种还是有点问题,g++编译报错,gcc编译只是警告。
首先,pthread_join()
的第二个参数是一个void **
类型的,我们传递void *ret
的地址进去,这时,ret
就是返回的地址了,我们要取的是地址里面的值,因为要转换成整形输出,所以void *
要强制转换为int *
,然后取星号,得到线程传出的值,即*(int *)ret
,所以第二种写法,还是欠妥当的。
但是,第一种写法,要是在栈上为ret
分配空间,会出现段错误。这个是因为,当print()
函数结束时,就自动释放了栈地址空间,我们在main()
函数还要访问,就会导致段错误了,因为我们访问了一段未知的地址空间。而堆空间是由程序员释放,程序员没释放就等程序运行结束系统自动释放。
第二种写法为什么用gcc
编译也能通过,只是有警告信息,这里是强行将地址转化为了整数,竟然和线程返回的值是一样的,奇奇怪怪。
但是,这样子想想,第二种写法,不也是泄露的内存?函数都执行完了,不释放资源?
应该还有更好的、更优秀的写法,希望大家多多指点。
段错误产生的原因
man pthread_cancel
#include
int pthread_cancel(pthread_t thread);
Compile and link with -pthread
#include
#include
#include
void *print(void *arg) {
while (1) {
printf("I am a thread, tid = %lu\n", pthread_self());
sleep(1);
}
return NULL;
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, print, NULL);
sleep(5); // 防止主线程比子线程先结束
if (pthread_cancel(tid) == 0) {
printf("success!\n");
} else {
perror("fault...");
}
pthread_join(tid, NULL);
return 0;
}
线程如果是被pthread_cancel
取消的,返回值为-1,#define PTHREAD_CANCELED((void *)-1)
但是,这里就有个问题,用之前第一种方法 *(int *)ret
,就会发生段错误,因为我们访问的是未知的地址空间,我也很迷惑啊~
注意,线程中必须有取消点才能杀死线程。查看所有取消点man 7 pthreads
,强行设置取消点使用pthread_testcancel()
函数。
man pthread_detach
#include
int pthread_detach(pthread_t thread);
Compile and link with -pthread.
实现线程分离不需要pthread_join()
回收资源,如果用了,会出问题。
#include
#include
#include
#include
void *print(void *arg) {
printf("I am thread, tid = %lu\n", pthread_self());
sleep(4);
return NULL;
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, print, NULL);
printf("I am main thread, tid = %lu\n", pthread_self());
sleep(5);
pthread_detach(tid);
int ret = 0;
if ((ret = pthread_join(tid, NULL)) > 0) {
printf("join error: %d, %s\n", ret, strerror(ret));
}
return 0;
}
man pthread_attr_init
初始化线程属性
man pthreaed_attr_destroy
销毁线程属性
#include
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
Compile and link with -pthread.
man pthread_attr_setdetachstate
设置属性分离
#include
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
man pthread_mutex_init
初始化锁,销毁锁。
#include
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
man pthread_mutex_lock
给共享资源加锁。
如果未加锁,则给该线程加锁。
如果已经加锁,阻塞等待。
#include
int pthread_mutex_lock(pthread_mutex_t *mutex);
#include
#include
#include
#include
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int sum = 0;
void *print1(void *arg) {
while (1) {
pthread_mutex_lock(&mutex);
printf("1");
sleep(rand() % 3);
printf("2\n");
pthread_mutex_unlock(&mutex);
sleep(rand() % 3);
}
}
void *print2(void *arg) {
while (1) {
pthread_mutex_lock(&mutex);
printf("3");
sleep(rand() % 3);
printf("4\n");
pthread_mutex_unlock(&mutex);
sleep(rand() % 3);
}
}
int main() {
pthread_t tid[2];
pthread_create(&tid[0], NULL, print1, NULL);
pthread_create(&tid[1], NULL, print2, NULL);
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
return 0;
}
man pthread_rwlock_rdlock
读锁
#include
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
man pthread_rwlock_wrlock
写锁
#include
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
使用的是否声明全局变量pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER
传&rwlock
进去即可。
man sem_init
#include
int sem_init(sem_t *sem, int pshared, unsigned int value);
man sem_destroy
#include
int sem_destroy(sem_t *sem);
man sem_wait
#include
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
申请信号量,成功value–,当信号量为0时,阻塞等待
man sem_post
#include
int sem_post(sem_t *sem);
释放信号量,value++。
Linux C 实现生产者消费者问题
多线程之间的资源共享还是比进程方便些。多线程内容还有很多,还要慢慢学习。
睡眠排序:
#include
#include
#include
#include
#include
using namespace std;
vector<int> vec;
vector<int> ans;
int sum = 0;
template <class T>
void print(const T &array) {
for (int num : array) {
cout << num << " ";
}
cout << endl;
}
void create_numbers(int cnt) {
for (int i = 0; i < cnt; ++i) {
int tmp = rand() % 10 + 1;
sum += tmp;
vec.emplace_back(tmp);
}
cout << "before sort: ";
print(vec);
}
void *func(void *arg) {
sleep(*(int *)arg);
ans.emplace_back(*(int *)arg);
return NULL;
}
int main() {
srand((unsigned int)time(nullptr));
int cnt = 10;
create_numbers(cnt);
pthread_t tid[cnt];
int i;
for (i = 0; i < cnt; ++i) {
int *argc = new int(vec[i]);
pthread_create(&tid[i], NULL, func, (void *)argc);
pthread_detach(tid[i]);
}
sleep(sum);
cout << "sort after: ";
print(ans);
return 0;
}