Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 一些线程在被大量调用时永远无法执行_C_Linux_Multithreading_Pthreads - Fatal编程技术网

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?并不是说互斥体比原子更容易理解,互斥体是隐藏在引擎盖下的原子。它适用于像这样一个简单的程序,但并不是解决几乎所有实际问题的合适方法。你说的是:“来,用这个手榴弹打开瓶子。”开瓶器是更合适的工具。“对于几乎所有的实际问题都不是一个合适的解决方案”这是一个计数器,原子计数器在线程编程中无处不在。它们是整个低争用信号量类的同步原语。在这里,我们不得不同意不同意。