C 一些线程在被大量调用时永远无法执行
考虑以下程序C 一些线程在被大量调用时永远无法执行,c,linux,multithreading,pthreads,C,Linux,Multithreading,Pthreads,考虑以下程序 static long count = 0; void thread() { printf("%d\n",++count); } int main() { pthread_t t; sigset_t set; int i,limit = 30000; struct rlimit rlim; getrlimit(RLIMIT_NPROC, &rlim); rlim.rlim_cur = rlim.rlim_max;
static long count = 0;
void thread()
{
printf("%d\n",++count);
}
int main()
{
pthread_t t;
sigset_t set;
int i,limit = 30000;
struct rlimit rlim;
getrlimit(RLIMIT_NPROC, &rlim);
rlim.rlim_cur = rlim.rlim_max;
setrlimit(RLIMIT_NPROC, &rlim);
for(i=0; i<limit; i++) {
if(pthread_create(&t,NULL,(void *(*)(void*))thread, NULL) != 0) {
printf("thread creation failed\n");
return -1;
}
}
sigemptyset(&set);
sigsuspend(&set);
return 0;
}
静态长计数=0;
无效线程()
{
printf(“%d\n”++计数);
}
int main()
{
pthread_t;
sigset\u t集;
int i,限值=30000;
结构rlimit-rlim;
getrlimit(RLIMIT_NPROC和rlim);
rlim.rlim_cur=rlim.rlim_max;
setrlimit(RLIMIT_NPROC和rlim);
对于(i=0;i
为什么会这样
因为您有一个数据竞争(未定义的行为)
特别是,本声明:
printf("%d\n",++count);
在没有任何锁定的情况下修改全局(共享)变量。由于++
不会自动递增它,因此多个线程很可能读取相同的值(例如1234),递增它,并并行存储更新的值,从而导致重复打印1235(两次或更多次),并且一个或多个增量丢失
典型的解决方案是使用互斥来避免数据竞争,或者(很少)使用原子变量(保证原子增量)注意:原子变量很难正确使用。您还没有准备好使用它们。因为count
不是原子变量,所以在增量和后续打印中都有竞争条件
您需要的指令是atomic\u fetch\u add
,以增加计数器并避免争用条件。上的示例说明了您提出的确切问题
您的示例只需稍作调整即可使用:
#include <stdio.h>
#include <signal.h>
#include <sys/resource.h>
#include <pthread.h>
#include <stdatomic.h>
static atomic_long count = 1;
void * thread(void *data)
{
printf("%ld\n", atomic_fetch_add(&count, 1));
return NULL;
}
int main()
{
pthread_t t;
sigset_t set;
int i,limit = 30000;
struct rlimit rlim;
getrlimit(RLIMIT_NPROC, &rlim);
rlim.rlim_cur = rlim.rlim_max;
setrlimit(RLIMIT_NPROC, &rlim);
for(i=0; i<limit; i++) {
if(pthread_create(&t, NULL, thread, NULL) != 0) {
printf("thread creation failed\n");
return -1;
}
}
sigemptyset(&set);
sigsuspend(&set);
return 0;
}
#包括
#包括
#包括
#包括
#包括
静态原子长计数=1;
void*线程(void*数据)
{
printf(“%ld\n”,原子提取添加(&count,1));
返回NULL;
}
int main()
{
pthread_t;
sigset\u t集;
int i,限值=30000;
结构rlimit-rlim;
getrlimit(RLIMIT_NPROC和rlim);
rlim.rlim_cur=rlim.rlim_max;
setrlimit(RLIMIT_NPROC和rlim);
(i=0;为什么要打印?为什么您的线程函数不使用正确的签名?未保护的使用<代码>计数<代码>是一个竞争条件;考虑使用C11原子类型。可能的副本,等等。为什么它不打印29945, 29999或29959?那些都在1和30000之间。“您需要的指令是原子获取添加"--不,他需要一个互斥锁。原子变量不适合初学者。@EmployedRussian不,他不需要?Atomic\u fetch\u add
会给他一份原子中数据的副本,并以原子方式递增计数器。计数器是显式使用的用例Atomic\u fetch\u add
。你有解释为什么它不会这样做吗rk?并不是说互斥体比原子更容易理解,互斥体是隐藏在引擎盖下的原子。它适用于像这样一个简单的程序,但并不是解决几乎所有实际问题的合适方法。你说的是:“来,用这个手榴弹打开瓶子。”开瓶器是更合适的工具。“对于几乎所有的实际问题都不是一个合适的解决方案”这是一个计数器,原子计数器在线程编程中无处不在。它们是整个低争用信号量类的同步原语。在这里,我们不得不同意不同意。